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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1ef8aab90f4a3bec0602ae96afb11f6c74d7b8b045bfb7bb649be8a6a5df61c
4
- data.tar.gz: f86cbe57dab02bab4b7f93096b94e73d7948f740a017beee8d44b7cf1b274a88
3
+ metadata.gz: 204e1595877682d96997ee193c8b0aa0230d6f5e1c22d37ca515e1e94a40d404
4
+ data.tar.gz: 4a373acd12bdd3451bda93d7186a69a217aeeea593c3ad1d8cb425d1f215d0cc
5
5
  SHA512:
6
- metadata.gz: 4b56ad88170012a6d956a097bfef88ccfe63a24db56e06432babbbac530ef24f0a20f43e30ddf62a604f05e80eafed1ba718b6a06733c3208d5c36dda16670c7
7
- data.tar.gz: 2ce859941cd08128e364f4cab359dd5bc17d5d7b480bd709c38ef44762becc569cc126aac0d86258e86cb9c3172d623cd8341df7167004df5948469f9670c8cc
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.to_s == 'true'
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
- time_execution = test_file.fetch('time_execution')
14
- time_execution >= time_threshold && time_execution > 0
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
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KnapsackPro
4
- VERSION = '7.11.0'
4
+ VERSION = '7.12.1'
5
5
  end
@@ -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
- context 'when ENV exists' do
1020
- before { stub_const("ENV", { 'KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES' => true }) }
1021
- it { should eq true }
1019
+ before do
1020
+ described_class.remove_instance_variable(:@rspec_split_by_test_examples)
1021
+ rescue NameError
1022
1022
  end
1023
1023
 
1024
- context "when ENV doesn't exist" do
1025
- before { stub_const("ENV", {}) }
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
- describe '.rspec_split_by_test_examples?' do
1031
- subject { described_class.rspec_split_by_test_examples? }
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
- context 'when ENV exists' do
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 KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=false' do
1040
- before { stub_const("ENV", { 'KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES' => 'false' }) }
1041
- it { should be false }
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 { stub_const("ENV", {}) }
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 execution' do
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 no recorded time execution' do
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.11.0
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-10-30 00:00:00.000000000 Z
11
+ date: 2024-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake