knapsack_pro 7.11.0 → 7.12.0

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: b6e9369d803759d8590a88b3e34bc3e195ca6520ee6f97e41c312735a768a8bb
4
+ data.tar.gz: 45dd6b4b8871cd370ec44384b706a0445cce6276b0463bc307d36f79dea16deb
5
5
  SHA512:
6
- metadata.gz: 4b56ad88170012a6d956a097bfef88ccfe63a24db56e06432babbbac530ef24f0a20f43e30ddf62a604f05e80eafed1ba718b6a06733c3208d5c36dda16670c7
7
- data.tar.gz: 2ce859941cd08128e364f4cab359dd5bc17d5d7b480bd709c38ef44762becc569cc126aac0d86258e86cb9c3172d623cd8341df7167004df5948469f9670c8cc
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,14 @@
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
+
3
12
  ### 7.11.0
4
13
 
5
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
@@ -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
- 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.0'
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
@@ -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
- expect(allocator_builder).to receive(:get_slow_test_files).and_return(slow_test_files)
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 slow test files are detected' do
147
- let(:slow_test_files) do
148
- [
149
- '1_spec.rb',
150
- '2_spec.rb',
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
- it 'returns test files with test cases' do
155
- test_file_cases = double
156
- expect(adapter_class).to receive(:test_file_cases_for).with(slow_test_files).and_return(test_file_cases)
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
- test_files_with_test_cases = double
159
- expect(KnapsackPro::TestFilesWithTestCasesComposer).to receive(:call).with(test_files_to_run, slow_test_files, test_file_cases).and_return(test_files_with_test_cases)
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
- expect(subject).to eq test_files_with_test_cases
178
+ expect(subject).to eq test_files_with_test_cases
179
+ end
162
180
  end
163
- end
164
181
 
165
- context 'when slow test files are not detected' do
166
- let(:slow_test_files) { [] }
182
+ context 'when slow test files are not detected' do
183
+ let(:slow_test_files) { [] }
167
184
 
168
- it 'returns test files without test cases' do
169
- expect(subject).to eq test_files_to_run
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 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.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-30 00:00:00.000000000 Z
11
+ date: 2024-10-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake