knapsack_pro 7.11.0 → 7.12.1
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 +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
|