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 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