knapsack_pro 7.10.0 → 7.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +9 -0
- data/CHANGELOG.md +17 -0
- data/knapsack_pro.gemspec +1 -0
- data/lib/knapsack_pro/base_allocator_builder.rb +5 -0
- data/lib/knapsack_pro/config/env.rb +8 -0
- data/lib/knapsack_pro/slow_test_file_determiner.rb +6 -2
- data/lib/knapsack_pro/test_case_mergers/rspec_merger.rb +22 -6
- data/lib/knapsack_pro/version.rb +1 -1
- data/spec/integration/runners/queue/rspec_runner_spec.rb +21 -5
- data/spec/knapsack_pro/base_allocator_builder_spec.rb +36 -18
- data/spec/knapsack_pro/config/env_spec.rb +31 -0
- data/spec/knapsack_pro/slow_test_file_determiner_spec.rb +25 -3
- data/spec/knapsack_pro/test_case_mergers/rspec_merger_spec.rb +40 -18
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b6e9369d803759d8590a88b3e34bc3e195ca6520ee6f97e41c312735a768a8bb
|
4
|
+
data.tar.gz: 45dd6b4b8871cd370ec44384b706a0445cce6276b0463bc307d36f79dea16deb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a0a3f3301f24a840845b0a59d40f06aa94d1ce94d1156846f740f237606c54a05b32da7d44ee815a65674c35ca94ac63185b0d93262570c3379e60a3686872f
|
7
|
+
data.tar.gz: 12f877a2c3e060580c3b2f20fc1de7fb934c47c82f1dfa95a1b240ab82838cf6580c9325fbba494849e14515634084cc12b294224412e2e63d5aa36810572d98
|
data/.circleci/config.yml
CHANGED
@@ -268,6 +268,15 @@ jobs:
|
|
268
268
|
export KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true
|
269
269
|
export KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true
|
270
270
|
bundle exec rake knapsack_pro:queue:rspec
|
271
|
+
- run:
|
272
|
+
working_directory: ~/rails-app-with-knapsack_pro
|
273
|
+
command: |
|
274
|
+
# split by test examples above the slow test file threshold ||
|
275
|
+
export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--$CIRCLE_BUILD_NUM--queue--split-above-slow-test-file-threshold"
|
276
|
+
export KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true
|
277
|
+
export KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true
|
278
|
+
export KNAPSACK_PRO_SLOW_TEST_FILE_THRESHOLD=1
|
279
|
+
bundle exec rake knapsack_pro:queue:rspec
|
271
280
|
- run:
|
272
281
|
working_directory: ~/rails-app-with-knapsack_pro
|
273
282
|
command: |
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,22 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
### 7.12.0
|
4
|
+
|
5
|
+
* Add `KNAPSACK_PRO_SLOW_TEST_FILE_THRESHOLD` to improve the RSpec split by examples feature with many skipped tests
|
6
|
+
* Do not split test files by test cases if you run tests on a single CI node to run Knapsack Pro faster.
|
7
|
+
|
8
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/pull/282
|
9
|
+
|
10
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v7.11.0...v7.12.0
|
11
|
+
|
12
|
+
### 7.11.0
|
13
|
+
|
14
|
+
* fix(RSpec split by examples): Properly determine slow test files when test example execution times and full test file execution time are both known
|
15
|
+
|
16
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/pull/281
|
17
|
+
|
18
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v7.10.0...v7.11.0
|
19
|
+
|
3
20
|
### 7.10.0
|
4
21
|
|
5
22
|
* Improve the RSpec split by examples feature. Use test file execution times for existing test files on the disk to determine slow test files. This fixes issue with detecting slow test files when API token is shared between multiple test suites.
|
data/knapsack_pro.gemspec
CHANGED
@@ -36,6 +36,11 @@ module KnapsackPro
|
|
36
36
|
test_files_to_run = all_test_files_to_run
|
37
37
|
|
38
38
|
if adapter_class.split_by_test_cases_enabled?
|
39
|
+
if KnapsackPro::Config::Env.ci_node_total < 2
|
40
|
+
KnapsackPro.logger.warn('Skipping split of test files by test cases because you are running tests on a single CI node (no parallelism)')
|
41
|
+
return test_files_to_run
|
42
|
+
end
|
43
|
+
|
39
44
|
slow_test_files = get_slow_test_files
|
40
45
|
return test_files_to_run if slow_test_files.empty?
|
41
46
|
|
@@ -200,6 +200,14 @@ module KnapsackPro
|
|
200
200
|
ENV.fetch('KNAPSACK_PRO_RSPEC_TEST_EXAMPLE_DETECTOR_PREFIX', 'bundle exec')
|
201
201
|
end
|
202
202
|
|
203
|
+
def slow_test_file_threshold
|
204
|
+
ENV.fetch('KNAPSACK_PRO_SLOW_TEST_FILE_THRESHOLD', nil)&.to_f
|
205
|
+
end
|
206
|
+
|
207
|
+
def slow_test_file_threshold?
|
208
|
+
!!slow_test_file_threshold
|
209
|
+
end
|
210
|
+
|
203
211
|
def test_suite_token
|
204
212
|
env_name = 'KNAPSACK_PRO_TEST_SUITE_TOKEN'
|
205
213
|
ENV[env_name] || raise("Missing environment variable #{env_name}. You should set environment variable like #{env_name}_RSPEC (note there is suffix _RSPEC at the end). knapsack_pro gem will set #{env_name} based on #{env_name}_RSPEC value. If you use other test runner than RSpec then use proper suffix.")
|
@@ -10,8 +10,12 @@ module KnapsackPro
|
|
10
10
|
time_threshold = (total_execution_time / KnapsackPro::Config::Env.ci_node_total) * TIME_THRESHOLD_PER_CI_NODE
|
11
11
|
|
12
12
|
test_files.select do |test_file|
|
13
|
-
|
14
|
-
|
13
|
+
execution_time = test_file.fetch('time_execution')
|
14
|
+
next false if execution_time.zero?
|
15
|
+
next true if execution_time >= time_threshold
|
16
|
+
next false unless KnapsackPro::Config::Env.slow_test_file_threshold?
|
17
|
+
|
18
|
+
execution_time >= KnapsackPro::Config::Env.slow_test_file_threshold
|
15
19
|
end
|
16
20
|
end
|
17
21
|
|
@@ -4,17 +4,27 @@ module KnapsackPro
|
|
4
4
|
module TestCaseMergers
|
5
5
|
class RSpecMerger < BaseMerger
|
6
6
|
def call
|
7
|
-
|
7
|
+
all_test_files_hash = {}
|
8
|
+
merged_test_file_examples_hash = {}
|
9
|
+
|
8
10
|
test_files.each do |test_file|
|
9
|
-
|
11
|
+
path = test_file.fetch('path')
|
12
|
+
test_file_path = extract_test_file_path(path)
|
13
|
+
|
14
|
+
if rspec_id_path?(path)
|
15
|
+
merged_test_file_examples_hash[test_file_path] ||= 0.0
|
16
|
+
merged_test_file_examples_hash[test_file_path] += test_file.fetch('time_execution')
|
17
|
+
else
|
18
|
+
all_test_files_hash[test_file_path] = test_file.fetch('time_execution')
|
19
|
+
end
|
20
|
+
end
|
10
21
|
|
11
|
-
|
12
|
-
|
13
|
-
merged_test_files_hash[test_file_path] += test_file.fetch('time_execution')
|
22
|
+
merged_test_file_examples_hash.each do |path, time_execution|
|
23
|
+
all_test_files_hash[path] = [time_execution, all_test_files_hash[path]].compact.max
|
14
24
|
end
|
15
25
|
|
16
26
|
merged_test_files = []
|
17
|
-
|
27
|
+
all_test_files_hash.each do |path, time_execution|
|
18
28
|
merged_test_files << {
|
19
29
|
'path' => path,
|
20
30
|
'time_execution' => time_execution
|
@@ -31,6 +41,12 @@ module KnapsackPro
|
|
31
41
|
def extract_test_file_path(path)
|
32
42
|
path.gsub(/\.rb\[.+\]$/, '.rb')
|
33
43
|
end
|
44
|
+
|
45
|
+
def rspec_id_path?(path)
|
46
|
+
path_with_id_regex = /.+_spec\.rb\[.+\]$/
|
47
|
+
|
48
|
+
path&.match?(path_with_id_regex)
|
49
|
+
end
|
34
50
|
end
|
35
51
|
end
|
36
52
|
end
|
data/lib/knapsack_pro/version.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'open3'
|
2
2
|
require 'json'
|
3
3
|
require 'nokogiri'
|
4
|
+
require 'ostruct'
|
4
5
|
|
5
6
|
describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :clear_tmp do
|
6
7
|
SPEC_DIRECTORY = 'spec_integration'
|
@@ -1061,7 +1062,7 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
|
|
1061
1062
|
expect(actual.stdout).to_not include('C1 test example')
|
1062
1063
|
|
1063
1064
|
expect(actual.stdout).to include('An error occurred while loading ./spec_integration/failing_spec.rb')
|
1064
|
-
expect(actual.stdout).to match(/undefined local variable or method
|
1065
|
+
expect(actual.stdout).to match(/undefined local variable or method .a_fake_method. for.* RSpec::ExampleGroups::BDescribe/)
|
1065
1066
|
expect(actual.stdout).to include('WARN -- : [knapsack_pro] RSpec wants to quit')
|
1066
1067
|
expect(actual.stdout).to include('1 example, 0 failures, 1 error occurred outside of examples')
|
1067
1068
|
|
@@ -1104,7 +1105,7 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
|
|
1104
1105
|
actual = subject
|
1105
1106
|
|
1106
1107
|
expect(actual.stdout).to include('An error occurred while loading spec_helper.')
|
1107
|
-
expect(actual.stdout).to
|
1108
|
+
expect(actual.stdout).to match(/undefined local variable or method .a_fake_method. for main/)
|
1108
1109
|
expect(actual.stdout).to include('0 examples, 0 failures, 1 error occurred outside of examples')
|
1109
1110
|
|
1110
1111
|
expect(actual.exit_code).to eq 1
|
@@ -1407,9 +1408,9 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
|
|
1407
1408
|
|
1408
1409
|
expect(actual.stdout).to include('Use the following backtrace(s) to find the line of code that got stuck if the CI node hung and terminated your tests.')
|
1409
1410
|
expect(actual.stdout).to include('Main thread backtrace:')
|
1410
|
-
expect(actual.stdout).to
|
1411
|
+
expect(actual.stdout).to match(/spec_integration\/b_spec\.rb:7:in .*kill/)
|
1411
1412
|
expect(actual.stdout).to include('Non-main thread backtrace:')
|
1412
|
-
expect(actual.stdout).to
|
1413
|
+
expect(actual.stdout).to match(/spec_integration\/a_spec\.rb:6:in .*sleep/)
|
1413
1414
|
|
1414
1415
|
|
1415
1416
|
expect(actual.exit_code).to eq 1
|
@@ -1963,10 +1964,13 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
|
|
1963
1964
|
# remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
|
1964
1965
|
# for the following slow test files
|
1965
1966
|
ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"
|
1967
|
+
|
1968
|
+
ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
|
1966
1969
|
end
|
1967
1970
|
after do
|
1968
1971
|
ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
|
1969
1972
|
ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
|
1973
|
+
ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
|
1970
1974
|
end
|
1971
1975
|
|
1972
1976
|
it 'splits slow test files by examples AND ensures the test examples are executed only once' do
|
@@ -2019,7 +2023,7 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
|
|
2019
2023
|
|
2020
2024
|
actual = subject
|
2021
2025
|
|
2022
|
-
expect(actual.stdout).to
|
2026
|
+
expect(actual.stdout).to match(/DEBUG -- : \[knapsack_pro\] Detected 1 slow test files: \[\{"path".?=>.?"spec_integration\/a_spec\.rb"\}\]/)
|
2023
2027
|
|
2024
2028
|
expect(actual.stdout).to include(
|
2025
2029
|
<<~OUTPUT
|
@@ -2059,10 +2063,13 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
|
|
2059
2063
|
# remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
|
2060
2064
|
# for the following slow test files
|
2061
2065
|
ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"
|
2066
|
+
|
2067
|
+
ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
|
2062
2068
|
end
|
2063
2069
|
after do
|
2064
2070
|
ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
|
2065
2071
|
ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
|
2072
|
+
ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
|
2066
2073
|
end
|
2067
2074
|
|
2068
2075
|
it 'sets 1 as exit code AND raises an error (a test example path as a_spec.rb[1:1] would always be executed even when it does not have the tag that is set via the --tag option. We cannot run tests because it could lead to running unintentional tests)' do
|
@@ -2137,10 +2144,13 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
|
|
2137
2144
|
# remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
|
2138
2145
|
# for the following slow test files
|
2139
2146
|
ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"
|
2147
|
+
|
2148
|
+
ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
|
2140
2149
|
end
|
2141
2150
|
after do
|
2142
2151
|
ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
|
2143
2152
|
ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
|
2153
|
+
ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
|
2144
2154
|
end
|
2145
2155
|
|
2146
2156
|
it 'produces a JSON report' do
|
@@ -2236,10 +2246,13 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
|
|
2236
2246
|
# remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
|
2237
2247
|
# for the following slow test files
|
2238
2248
|
ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"
|
2249
|
+
|
2250
|
+
ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
|
2239
2251
|
end
|
2240
2252
|
after do
|
2241
2253
|
ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
|
2242
2254
|
ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
|
2255
|
+
ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
|
2243
2256
|
end
|
2244
2257
|
|
2245
2258
|
it 'produces a JUnit XML report' do
|
@@ -2333,10 +2346,13 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
|
|
2333
2346
|
# remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
|
2334
2347
|
# for the following slow test files
|
2335
2348
|
ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"
|
2349
|
+
|
2350
|
+
ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
|
2336
2351
|
end
|
2337
2352
|
after do
|
2338
2353
|
ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
|
2339
2354
|
ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
|
2355
|
+
ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
|
2340
2356
|
end
|
2341
2357
|
|
2342
2358
|
it 'produces a code coverage report' do
|
@@ -134,39 +134,57 @@ describe KnapsackPro::BaseAllocatorBuilder do
|
|
134
134
|
|
135
135
|
before do
|
136
136
|
expect(adapter_class).to receive(:split_by_test_cases_enabled?).and_return(true)
|
137
|
+
expect(KnapsackPro::Config::Env).to receive(:ci_node_total).and_return(node_total)
|
137
138
|
|
138
139
|
test_file_pattern = double
|
139
140
|
expect(KnapsackPro::TestFilePattern).to receive(:call).with(adapter_class).and_return(test_file_pattern)
|
140
141
|
|
141
142
|
expect(KnapsackPro::TestFileFinder).to receive(:call).with(test_file_pattern).and_return(test_files_to_run)
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'when less than 2 CI nodes' do
|
146
|
+
let(:node_total) { 1 }
|
142
147
|
|
143
|
-
|
148
|
+
it 'returns test files without test cases' do
|
149
|
+
logger = instance_double(Logger)
|
150
|
+
expect(KnapsackPro).to receive(:logger).and_return(logger)
|
151
|
+
expect(logger).to receive(:warn).with('Skipping split of test files by test cases because you are running tests on a single CI node (no parallelism)')
|
152
|
+
expect(subject).to eq test_files_to_run
|
153
|
+
end
|
144
154
|
end
|
145
155
|
|
146
|
-
context 'when
|
147
|
-
let(:
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
]
|
156
|
+
context 'when at least 2 CI nodes' do
|
157
|
+
let(:node_total) { 2 }
|
158
|
+
|
159
|
+
before do
|
160
|
+
expect(allocator_builder).to receive(:get_slow_test_files).and_return(slow_test_files)
|
152
161
|
end
|
153
162
|
|
154
|
-
|
155
|
-
|
156
|
-
|
163
|
+
context 'when slow test files are detected' do
|
164
|
+
let(:slow_test_files) do
|
165
|
+
[
|
166
|
+
'1_spec.rb',
|
167
|
+
'2_spec.rb',
|
168
|
+
]
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'returns test files with test cases' do
|
172
|
+
test_file_cases = double
|
173
|
+
expect(adapter_class).to receive(:test_file_cases_for).with(slow_test_files).and_return(test_file_cases)
|
157
174
|
|
158
|
-
|
159
|
-
|
175
|
+
test_files_with_test_cases = double
|
176
|
+
expect(KnapsackPro::TestFilesWithTestCasesComposer).to receive(:call).with(test_files_to_run, slow_test_files, test_file_cases).and_return(test_files_with_test_cases)
|
160
177
|
|
161
|
-
|
178
|
+
expect(subject).to eq test_files_with_test_cases
|
179
|
+
end
|
162
180
|
end
|
163
|
-
end
|
164
181
|
|
165
|
-
|
166
|
-
|
182
|
+
context 'when slow test files are not detected' do
|
183
|
+
let(:slow_test_files) { [] }
|
167
184
|
|
168
|
-
|
169
|
-
|
185
|
+
it 'returns test files without test cases' do
|
186
|
+
expect(subject).to eq test_files_to_run
|
187
|
+
end
|
170
188
|
end
|
171
189
|
end
|
172
190
|
end
|
@@ -1062,6 +1062,37 @@ describe KnapsackPro::Config::Env do
|
|
1062
1062
|
end
|
1063
1063
|
end
|
1064
1064
|
|
1065
|
+
describe '.slow_test_file_threshold' do
|
1066
|
+
subject { described_class.slow_test_file_threshold }
|
1067
|
+
|
1068
|
+
context 'when ENV exists' do
|
1069
|
+
before { stub_const("ENV", { 'KNAPSACK_PRO_SLOW_TEST_FILE_THRESHOLD' => '2' }) }
|
1070
|
+
it 'returns seconds' do
|
1071
|
+
expect(subject).to eq 2.0
|
1072
|
+
expect(subject).to be_a Float
|
1073
|
+
end
|
1074
|
+
end
|
1075
|
+
|
1076
|
+
context "when ENV doesn't exist" do
|
1077
|
+
before { stub_const("ENV", {}) }
|
1078
|
+
it { should be_nil }
|
1079
|
+
end
|
1080
|
+
end
|
1081
|
+
|
1082
|
+
describe '.slow_test_file_threshold?' do
|
1083
|
+
subject { described_class.slow_test_file_threshold? }
|
1084
|
+
|
1085
|
+
context 'when ENV exists' do
|
1086
|
+
before { stub_const("ENV", { 'KNAPSACK_PRO_SLOW_TEST_FILE_THRESHOLD' => '2' }) }
|
1087
|
+
it { should be true }
|
1088
|
+
end
|
1089
|
+
|
1090
|
+
context "when ENV doesn't exist" do
|
1091
|
+
before { stub_const("ENV", {}) }
|
1092
|
+
it { should be false }
|
1093
|
+
end
|
1094
|
+
end
|
1095
|
+
|
1065
1096
|
describe '.test_suite_token' do
|
1066
1097
|
subject { described_class.test_suite_token }
|
1067
1098
|
|
@@ -8,8 +8,7 @@ describe KnapsackPro::SlowTestFileDeterminer do
|
|
8
8
|
|
9
9
|
subject { described_class.call(test_files) }
|
10
10
|
|
11
|
-
context 'when test files have recorded time
|
12
|
-
let(:time_execution) { 20.0 }
|
11
|
+
context 'when test files have recorded execution time' do
|
13
12
|
let(:test_files) do
|
14
13
|
[
|
15
14
|
{ 'path' => 'a_spec.rb', 'time_execution' => 1.0 },
|
@@ -27,7 +26,30 @@ describe KnapsackPro::SlowTestFileDeterminer do
|
|
27
26
|
end
|
28
27
|
end
|
29
28
|
|
30
|
-
context 'when test files have
|
29
|
+
context 'when test files have recorded execution time AND slow test files threshold is set' do
|
30
|
+
let(:test_files) do
|
31
|
+
[
|
32
|
+
{ 'path' => 'a_spec.rb', 'time_execution' => 1.0 },
|
33
|
+
{ 'path' => 'b_spec.rb', 'time_execution' => 3.4 },
|
34
|
+
{ 'path' => 'c_spec.rb', 'time_execution' => 3.5 },
|
35
|
+
{ 'path' => 'd_spec.rb', 'time_execution' => 12.1 },
|
36
|
+
]
|
37
|
+
end
|
38
|
+
|
39
|
+
before do
|
40
|
+
stub_const("ENV", { 'KNAPSACK_PRO_SLOW_TEST_FILE_THRESHOLD' => '2' })
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'detects slow tests above 2.0s threshold' do
|
44
|
+
expect(subject).to eq([
|
45
|
+
{ 'path' => 'b_spec.rb', 'time_execution' => 3.4 },
|
46
|
+
{ 'path' => 'c_spec.rb', 'time_execution' => 3.5 },
|
47
|
+
{ 'path' => 'd_spec.rb', 'time_execution' => 12.1 },
|
48
|
+
])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'when test files have no recorded execution time' do
|
31
53
|
let(:test_files) do
|
32
54
|
[
|
33
55
|
{ 'path' => 'a_spec.rb', 'time_execution' => 0.0 },
|
@@ -2,7 +2,7 @@ describe KnapsackPro::TestCaseMergers::RSpecMerger do
|
|
2
2
|
describe '#call' do
|
3
3
|
subject { described_class.new(test_files).call }
|
4
4
|
|
5
|
-
context 'when
|
5
|
+
context 'when test files are regular file paths (not test example paths)' do
|
6
6
|
let(:test_files) do
|
7
7
|
[
|
8
8
|
{ 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
|
@@ -10,7 +10,7 @@ describe KnapsackPro::TestCaseMergers::RSpecMerger do
|
|
10
10
|
]
|
11
11
|
end
|
12
12
|
|
13
|
-
it do
|
13
|
+
it 'returns the test files unchanged' do
|
14
14
|
expect(subject).to eq([
|
15
15
|
{ 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
|
16
16
|
{ 'path' => 'spec/b_spec.rb', 'time_execution' => 2.2 },
|
@@ -28,7 +28,7 @@ describe KnapsackPro::TestCaseMergers::RSpecMerger do
|
|
28
28
|
]
|
29
29
|
end
|
30
30
|
|
31
|
-
it '
|
31
|
+
it 'merges the test example paths and sums their execution times' do
|
32
32
|
expect(subject).to eq([
|
33
33
|
{ 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
|
34
34
|
{ 'path' => 'spec/test_case_spec.rb', 'time_execution' => 3.0 },
|
@@ -36,23 +36,45 @@ describe KnapsackPro::TestCaseMergers::RSpecMerger do
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
context 'when test files have test example paths and
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
39
|
+
context 'when test files have test example paths and the full test file path exists simultaneously' do
|
40
|
+
context 'when the full test file path has a higher execution time than the sum of test example paths' do
|
41
|
+
let(:test_files) do
|
42
|
+
[
|
43
|
+
{ 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
|
44
|
+
# full test file path exists alongside test example paths
|
45
|
+
{ 'path' => 'spec/test_case_spec.rb', 'time_execution' => 3.1 },
|
46
|
+
# test example paths
|
47
|
+
{ 'path' => 'spec/test_case_spec.rb[1:1]', 'time_execution' => 2.2 },
|
48
|
+
{ 'path' => 'spec/test_case_spec.rb[1:2]', 'time_execution' => 0.8 },
|
49
|
+
]
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'returns the full test file path execution time' do
|
53
|
+
expect(subject).to eq([
|
54
|
+
{ 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
|
55
|
+
{ 'path' => 'spec/test_case_spec.rb', 'time_execution' => 3.1 },
|
56
|
+
])
|
57
|
+
end
|
49
58
|
end
|
50
59
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
60
|
+
context 'when the full test file path has a lower execution time than the sum of test example paths' do
|
61
|
+
let(:test_files) do
|
62
|
+
[
|
63
|
+
{ 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
|
64
|
+
# full test file path exists alongside test example paths
|
65
|
+
{ 'path' => 'spec/test_case_spec.rb', 'time_execution' => 2.9 },
|
66
|
+
# test example paths
|
67
|
+
{ 'path' => 'spec/test_case_spec.rb[1:1]', 'time_execution' => 2.2 },
|
68
|
+
{ 'path' => 'spec/test_case_spec.rb[1:2]', 'time_execution' => 0.8 },
|
69
|
+
]
|
70
|
+
end
|
71
|
+
|
72
|
+
it "returns the sum of test example paths' execution times" do
|
73
|
+
expect(subject).to eq([
|
74
|
+
{ 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
|
75
|
+
{ 'path' => 'spec/test_case_spec.rb', 'time_execution' => 3.0 },
|
76
|
+
])
|
77
|
+
end
|
56
78
|
end
|
57
79
|
end
|
58
80
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knapsack_pro
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.
|
4
|
+
version: 7.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ArturT
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-10-
|
11
|
+
date: 2024-10-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -178,6 +178,20 @@ dependencies:
|
|
178
178
|
- - ">="
|
179
179
|
- !ruby/object:Gem::Version
|
180
180
|
version: 0.9.9
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: ostruct
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: 0.6.0
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: 0.6.0
|
181
195
|
description: Knapsack Pro wraps your current test runner(s) and works with your existing
|
182
196
|
CI infrastructure to parallelize tests optimally. It dynamically splits your tests
|
183
197
|
based on up-to-date test execution data. It's designed from the ground up for CI
|