knapsack_pro 7.11.0 → 7.12.1
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 +19 -0
- data/CHANGELOG.md +17 -0
- data/lib/knapsack_pro/config/env.rb +18 -5
- data/lib/knapsack_pro/slow_test_file_determiner.rb +6 -2
- data/lib/knapsack_pro/version.rb +1 -1
- data/spec/integration/runners/queue/rspec_runner_spec.rb +15 -0
- data/spec/knapsack_pro/config/env_spec.rb +67 -19
- data/spec/knapsack_pro/slow_test_file_determiner_spec.rb +25 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 204e1595877682d96997ee193c8b0aa0230d6f5e1c22d37ca515e1e94a40d404
|
4
|
+
data.tar.gz: 4a373acd12bdd3451bda93d7186a69a217aeeea593c3ad1d8cb425d1f215d0cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9f2310862a878b55c4001beaf3beda4c2249946a7fc04fe40f3b4e5911c17aff1ffc1df2437df392aa597681396cc1dc1e7a0deac67936d6e5cbf399bda830c5
|
7
|
+
data.tar.gz: a3d8b7bf464a71a5a0600333f017a981562ecab163c52f1b67747c5aaad444aab834ab7d0a93ef00cad012e2d4f66163ec1cfa9b9204e4bb13477b1fdce263de
|
data/.circleci/config.yml
CHANGED
@@ -268,6 +268,25 @@ 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
|
280
|
+
- run:
|
281
|
+
working_directory: ~/rails-app-with-knapsack_pro
|
282
|
+
command: |
|
283
|
+
# split by test examples AND a single CI node ||
|
284
|
+
export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--$CIRCLE_BUILD_NUM--queue--split--single-node"
|
285
|
+
export KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true
|
286
|
+
export KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true
|
287
|
+
export KNAPSACK_PRO_CI_NODE_TOTAL=1
|
288
|
+
export KNAPSACK_PRO_CI_NODE_INDEX=0
|
289
|
+
bundle exec rake knapsack_pro:queue:rspec
|
271
290
|
- run:
|
272
291
|
working_directory: ~/rails-app-with-knapsack_pro
|
273
292
|
command: |
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,22 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
### 7.12.1
|
4
|
+
|
5
|
+
* fix(RSpec split by examples): properly disable split by test examples on a single node to speed up tests
|
6
|
+
|
7
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/pull/283
|
8
|
+
|
9
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v7.12.0...v7.12.1
|
10
|
+
|
11
|
+
### 7.12.0
|
12
|
+
|
13
|
+
* Add `KNAPSACK_PRO_SLOW_TEST_FILE_THRESHOLD` to improve the RSpec split by examples feature with many skipped tests
|
14
|
+
* Do not split test files by test cases if you run tests on a single CI node to run Knapsack Pro faster.
|
15
|
+
|
16
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/pull/282
|
17
|
+
|
18
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v7.11.0...v7.12.0
|
19
|
+
|
3
20
|
### 7.11.0
|
4
21
|
|
5
22
|
* fix(RSpec split by examples): Properly determine slow test files when test example execution times and full test file execution time are both known
|
@@ -188,18 +188,31 @@ module KnapsackPro
|
|
188
188
|
ENV.fetch('KNAPSACK_PRO_CUCUMBER_QUEUE_PREFIX', 'bundle exec')
|
189
189
|
end
|
190
190
|
|
191
|
-
def rspec_split_by_test_examples
|
192
|
-
ENV.fetch('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES', false)
|
193
|
-
end
|
194
|
-
|
195
191
|
def rspec_split_by_test_examples?
|
196
|
-
rspec_split_by_test_examples
|
192
|
+
return @rspec_split_by_test_examples if defined?(@rspec_split_by_test_examples)
|
193
|
+
|
194
|
+
split = ENV.fetch('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES', false).to_s == 'true'
|
195
|
+
|
196
|
+
if split && ci_node_total < 2
|
197
|
+
KnapsackPro.logger.debug('Skipping split of test files by test examples because you are running tests on a single CI node (no parallelism)')
|
198
|
+
@rspec_split_by_test_examples = false
|
199
|
+
else
|
200
|
+
@rspec_split_by_test_examples = split
|
201
|
+
end
|
197
202
|
end
|
198
203
|
|
199
204
|
def rspec_test_example_detector_prefix
|
200
205
|
ENV.fetch('KNAPSACK_PRO_RSPEC_TEST_EXAMPLE_DETECTOR_PREFIX', 'bundle exec')
|
201
206
|
end
|
202
207
|
|
208
|
+
def slow_test_file_threshold
|
209
|
+
ENV.fetch('KNAPSACK_PRO_SLOW_TEST_FILE_THRESHOLD', nil)&.to_f
|
210
|
+
end
|
211
|
+
|
212
|
+
def slow_test_file_threshold?
|
213
|
+
!!slow_test_file_threshold
|
214
|
+
end
|
215
|
+
|
203
216
|
def test_suite_token
|
204
217
|
env_name = 'KNAPSACK_PRO_TEST_SUITE_TOKEN'
|
205
218
|
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
|
|
data/lib/knapsack_pro/version.rb
CHANGED
@@ -1964,10 +1964,13 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
|
|
1964
1964
|
# remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
|
1965
1965
|
# for the following slow test files
|
1966
1966
|
ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"
|
1967
|
+
|
1968
|
+
ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
|
1967
1969
|
end
|
1968
1970
|
after do
|
1969
1971
|
ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
|
1970
1972
|
ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
|
1973
|
+
ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
|
1971
1974
|
end
|
1972
1975
|
|
1973
1976
|
it 'splits slow test files by examples AND ensures the test examples are executed only once' do
|
@@ -2060,10 +2063,13 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
|
|
2060
2063
|
# remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
|
2061
2064
|
# for the following slow test files
|
2062
2065
|
ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"
|
2066
|
+
|
2067
|
+
ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
|
2063
2068
|
end
|
2064
2069
|
after do
|
2065
2070
|
ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
|
2066
2071
|
ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
|
2072
|
+
ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
|
2067
2073
|
end
|
2068
2074
|
|
2069
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
|
@@ -2138,10 +2144,13 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
|
|
2138
2144
|
# remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
|
2139
2145
|
# for the following slow test files
|
2140
2146
|
ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"
|
2147
|
+
|
2148
|
+
ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
|
2141
2149
|
end
|
2142
2150
|
after do
|
2143
2151
|
ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
|
2144
2152
|
ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
|
2153
|
+
ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
|
2145
2154
|
end
|
2146
2155
|
|
2147
2156
|
it 'produces a JSON report' do
|
@@ -2237,10 +2246,13 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
|
|
2237
2246
|
# remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
|
2238
2247
|
# for the following slow test files
|
2239
2248
|
ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"
|
2249
|
+
|
2250
|
+
ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
|
2240
2251
|
end
|
2241
2252
|
after do
|
2242
2253
|
ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
|
2243
2254
|
ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
|
2255
|
+
ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
|
2244
2256
|
end
|
2245
2257
|
|
2246
2258
|
it 'produces a JUnit XML report' do
|
@@ -2334,10 +2346,13 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
|
|
2334
2346
|
# remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
|
2335
2347
|
# for the following slow test files
|
2336
2348
|
ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"
|
2349
|
+
|
2350
|
+
ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
|
2337
2351
|
end
|
2338
2352
|
after do
|
2339
2353
|
ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
|
2340
2354
|
ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
|
2355
|
+
ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
|
2341
2356
|
end
|
2342
2357
|
|
2343
2358
|
it 'produces a code coverage report' do
|
@@ -1013,37 +1013,54 @@ describe KnapsackPro::Config::Env do
|
|
1013
1013
|
end
|
1014
1014
|
end
|
1015
1015
|
|
1016
|
-
describe '.rspec_split_by_test_examples' do
|
1017
|
-
subject { described_class.rspec_split_by_test_examples }
|
1016
|
+
describe '.rspec_split_by_test_examples?' do
|
1017
|
+
subject { described_class.rspec_split_by_test_examples? }
|
1018
1018
|
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1019
|
+
before do
|
1020
|
+
described_class.remove_instance_variable(:@rspec_split_by_test_examples)
|
1021
|
+
rescue NameError
|
1022
1022
|
end
|
1023
1023
|
|
1024
|
-
context
|
1025
|
-
before
|
1024
|
+
context 'when KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true AND KNAPSACK_PRO_CI_NODE_TOTAL >= 2' do
|
1025
|
+
before do
|
1026
|
+
stub_const("ENV", { 'KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES' => 'true', 'KNAPSACK_PRO_CI_NODE_TOTAL' => '2' })
|
1027
|
+
expect(KnapsackPro).not_to receive(:logger)
|
1028
|
+
end
|
1029
|
+
|
1030
|
+
it { should be true }
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
context 'when KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=false AND KNAPSACK_PRO_CI_NODE_TOTAL >= 2' do
|
1034
|
+
before do
|
1035
|
+
stub_const("ENV", { 'KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES' => 'false', 'KNAPSACK_PRO_CI_NODE_TOTAL' => '2' })
|
1036
|
+
expect(KnapsackPro).not_to receive(:logger)
|
1037
|
+
end
|
1038
|
+
|
1026
1039
|
it { should be false }
|
1027
1040
|
end
|
1028
|
-
end
|
1029
1041
|
|
1030
|
-
|
1031
|
-
|
1042
|
+
context 'when KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true AND KNAPSACK_PRO_CI_NODE_TOTAL < 2' do
|
1043
|
+
before { stub_const("ENV", { 'KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES' => 'true', 'KNAPSACK_PRO_CI_NODE_TOTAL' => '1' }) }
|
1032
1044
|
|
1033
|
-
|
1034
|
-
context 'when KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true' do
|
1035
|
-
before { stub_const("ENV", { 'KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES' => 'true' }) }
|
1036
|
-
it { should be true }
|
1037
|
-
end
|
1045
|
+
it { should be false }
|
1038
1046
|
|
1039
|
-
context 'when
|
1040
|
-
|
1041
|
-
|
1047
|
+
context 'when called twice' do
|
1048
|
+
it 'logs a debug message only once' do
|
1049
|
+
logger = instance_double(Logger)
|
1050
|
+
expect(KnapsackPro).to receive(:logger).and_return(logger)
|
1051
|
+
expect(logger).to receive(:debug).with('Skipping split of test files by test examples because you are running tests on a single CI node (no parallelism)')
|
1052
|
+
|
1053
|
+
2.times { described_class.rspec_split_by_test_examples? }
|
1054
|
+
end
|
1042
1055
|
end
|
1043
1056
|
end
|
1044
1057
|
|
1045
1058
|
context "when ENV doesn't exist" do
|
1046
|
-
before
|
1059
|
+
before do
|
1060
|
+
stub_const("ENV", {})
|
1061
|
+
expect(KnapsackPro).not_to receive(:logger)
|
1062
|
+
end
|
1063
|
+
|
1047
1064
|
it { should be false }
|
1048
1065
|
end
|
1049
1066
|
end
|
@@ -1062,6 +1079,37 @@ describe KnapsackPro::Config::Env do
|
|
1062
1079
|
end
|
1063
1080
|
end
|
1064
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 'returns seconds' do
|
1088
|
+
expect(subject).to eq 2.0
|
1089
|
+
expect(subject).to be_a Float
|
1090
|
+
end
|
1091
|
+
end
|
1092
|
+
|
1093
|
+
context "when ENV doesn't exist" do
|
1094
|
+
before { stub_const("ENV", {}) }
|
1095
|
+
it { should be_nil }
|
1096
|
+
end
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
describe '.slow_test_file_threshold?' do
|
1100
|
+
subject { described_class.slow_test_file_threshold? }
|
1101
|
+
|
1102
|
+
context 'when ENV exists' do
|
1103
|
+
before { stub_const("ENV", { 'KNAPSACK_PRO_SLOW_TEST_FILE_THRESHOLD' => '2' }) }
|
1104
|
+
it { should be true }
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
context "when ENV doesn't exist" do
|
1108
|
+
before { stub_const("ENV", {}) }
|
1109
|
+
it { should be false }
|
1110
|
+
end
|
1111
|
+
end
|
1112
|
+
|
1065
1113
|
describe '.test_suite_token' do
|
1066
1114
|
subject { described_class.test_suite_token }
|
1067
1115
|
|
@@ -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 },
|
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.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ArturT
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|