knapsack_pro 7.10.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: 173300dc2ec82a1b5a15005c91ac3ceb942c40acbb14fd2ba57e64d2a32b67d8
4
- data.tar.gz: c0c856044ce6773dce0968ebd620f4c49e1fea170c30d880af90ace2e1fb66c1
3
+ metadata.gz: b6e9369d803759d8590a88b3e34bc3e195ca6520ee6f97e41c312735a768a8bb
4
+ data.tar.gz: 45dd6b4b8871cd370ec44384b706a0445cce6276b0463bc307d36f79dea16deb
5
5
  SHA512:
6
- metadata.gz: e078dce53b72374ef499087c9675eea34272769a46154997e55dc06ab23e4da7fa016206297eed8b3cc660c5238a99b16177abb6f45c191e3bd38dc60c9cee6f
7
- data.tar.gz: 5a80b8cbc3dc3273e297693263a9223fab250d1ee6adbd2c6c909f904d35430f3403a1f9da92dc2709adc3f30f8311b8d05d34b6292e8952e1aae42c88f8f977
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,22 @@
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
+
12
+ ### 7.11.0
13
+
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
15
+
16
+ https://github.com/KnapsackPro/knapsack_pro-ruby/pull/281
17
+
18
+ https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v7.10.0...v7.11.0
19
+
3
20
  ### 7.10.0
4
21
 
5
22
  * Improve the RSpec split by examples feature. Use test file execution times for existing test files on the disk to determine slow test files. This fixes issue with detecting slow test files when API token is shared between multiple test suites.
data/knapsack_pro.gemspec CHANGED
@@ -39,4 +39,5 @@ Gem::Specification.new do |spec|
39
39
  spec.add_development_dependency 'vcr', '>= 6.0'
40
40
  spec.add_development_dependency 'webmock', '>= 3.13'
41
41
  spec.add_development_dependency 'timecop', '>= 0.9.9'
42
+ spec.add_development_dependency 'ostruct', '>= 0.6.0'
42
43
  end
@@ -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
 
@@ -4,17 +4,27 @@ module KnapsackPro
4
4
  module TestCaseMergers
5
5
  class RSpecMerger < BaseMerger
6
6
  def call
7
- merged_test_files_hash = {}
7
+ all_test_files_hash = {}
8
+ merged_test_file_examples_hash = {}
9
+
8
10
  test_files.each do |test_file|
9
- test_file_path = extract_test_file_path(test_file.fetch('path'))
11
+ path = test_file.fetch('path')
12
+ test_file_path = extract_test_file_path(path)
13
+
14
+ if rspec_id_path?(path)
15
+ merged_test_file_examples_hash[test_file_path] ||= 0.0
16
+ merged_test_file_examples_hash[test_file_path] += test_file.fetch('time_execution')
17
+ else
18
+ all_test_files_hash[test_file_path] = test_file.fetch('time_execution')
19
+ end
20
+ end
10
21
 
11
- # must be float (default type for time execution from API)
12
- merged_test_files_hash[test_file_path] ||= 0.0
13
- merged_test_files_hash[test_file_path] += test_file.fetch('time_execution')
22
+ merged_test_file_examples_hash.each do |path, time_execution|
23
+ all_test_files_hash[path] = [time_execution, all_test_files_hash[path]].compact.max
14
24
  end
15
25
 
16
26
  merged_test_files = []
17
- merged_test_files_hash.each do |path, time_execution|
27
+ all_test_files_hash.each do |path, time_execution|
18
28
  merged_test_files << {
19
29
  'path' => path,
20
30
  'time_execution' => time_execution
@@ -31,6 +41,12 @@ module KnapsackPro
31
41
  def extract_test_file_path(path)
32
42
  path.gsub(/\.rb\[.+\]$/, '.rb')
33
43
  end
44
+
45
+ def rspec_id_path?(path)
46
+ path_with_id_regex = /.+_spec\.rb\[.+\]$/
47
+
48
+ path&.match?(path_with_id_regex)
49
+ end
34
50
  end
35
51
  end
36
52
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KnapsackPro
4
- VERSION = '7.10.0'
4
+ VERSION = '7.12.0'
5
5
  end
@@ -1,6 +1,7 @@
1
1
  require 'open3'
2
2
  require 'json'
3
3
  require 'nokogiri'
4
+ require 'ostruct'
4
5
 
5
6
  describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :clear_tmp do
6
7
  SPEC_DIRECTORY = 'spec_integration'
@@ -1061,7 +1062,7 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
1061
1062
  expect(actual.stdout).to_not include('C1 test example')
1062
1063
 
1063
1064
  expect(actual.stdout).to include('An error occurred while loading ./spec_integration/failing_spec.rb')
1064
- expect(actual.stdout).to match(/undefined local variable or method `a_fake_method' for.* RSpec::ExampleGroups::BDescribe/)
1065
+ expect(actual.stdout).to match(/undefined local variable or method .a_fake_method. for.* RSpec::ExampleGroups::BDescribe/)
1065
1066
  expect(actual.stdout).to include('WARN -- : [knapsack_pro] RSpec wants to quit')
1066
1067
  expect(actual.stdout).to include('1 example, 0 failures, 1 error occurred outside of examples')
1067
1068
 
@@ -1104,7 +1105,7 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
1104
1105
  actual = subject
1105
1106
 
1106
1107
  expect(actual.stdout).to include('An error occurred while loading spec_helper.')
1107
- expect(actual.stdout).to include("undefined local variable or method `a_fake_method' for main")
1108
+ expect(actual.stdout).to match(/undefined local variable or method .a_fake_method. for main/)
1108
1109
  expect(actual.stdout).to include('0 examples, 0 failures, 1 error occurred outside of examples')
1109
1110
 
1110
1111
  expect(actual.exit_code).to eq 1
@@ -1407,9 +1408,9 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
1407
1408
 
1408
1409
  expect(actual.stdout).to include('Use the following backtrace(s) to find the line of code that got stuck if the CI node hung and terminated your tests.')
1409
1410
  expect(actual.stdout).to include('Main thread backtrace:')
1410
- expect(actual.stdout).to include("spec_integration/b_spec.rb:7:in `kill'")
1411
+ expect(actual.stdout).to match(/spec_integration\/b_spec\.rb:7:in .*kill/)
1411
1412
  expect(actual.stdout).to include('Non-main thread backtrace:')
1412
- expect(actual.stdout).to include("spec_integration/a_spec.rb:6:in `sleep'")
1413
+ expect(actual.stdout).to match(/spec_integration\/a_spec\.rb:6:in .*sleep/)
1413
1414
 
1414
1415
 
1415
1416
  expect(actual.exit_code).to eq 1
@@ -1963,10 +1964,13 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
1963
1964
  # remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
1964
1965
  # for the following slow test files
1965
1966
  ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"
1967
+
1968
+ ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
1966
1969
  end
1967
1970
  after do
1968
1971
  ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
1969
1972
  ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
1973
+ ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
1970
1974
  end
1971
1975
 
1972
1976
  it 'splits slow test files by examples AND ensures the test examples are executed only once' do
@@ -2019,7 +2023,7 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
2019
2023
 
2020
2024
  actual = subject
2021
2025
 
2022
- expect(actual.stdout).to include('DEBUG -- : [knapsack_pro] Detected 1 slow test files: [{"path"=>"spec_integration/a_spec.rb"}]')
2026
+ expect(actual.stdout).to match(/DEBUG -- : \[knapsack_pro\] Detected 1 slow test files: \[\{"path".?=>.?"spec_integration\/a_spec\.rb"\}\]/)
2023
2027
 
2024
2028
  expect(actual.stdout).to include(
2025
2029
  <<~OUTPUT
@@ -2059,10 +2063,13 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
2059
2063
  # remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
2060
2064
  # for the following slow test files
2061
2065
  ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"
2066
+
2067
+ ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
2062
2068
  end
2063
2069
  after do
2064
2070
  ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
2065
2071
  ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
2072
+ ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
2066
2073
  end
2067
2074
 
2068
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
@@ -2137,10 +2144,13 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
2137
2144
  # remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
2138
2145
  # for the following slow test files
2139
2146
  ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"
2147
+
2148
+ ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
2140
2149
  end
2141
2150
  after do
2142
2151
  ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
2143
2152
  ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
2153
+ ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
2144
2154
  end
2145
2155
 
2146
2156
  it 'produces a JSON report' do
@@ -2236,10 +2246,13 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
2236
2246
  # remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
2237
2247
  # for the following slow test files
2238
2248
  ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"
2249
+
2250
+ ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
2239
2251
  end
2240
2252
  after do
2241
2253
  ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
2242
2254
  ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
2255
+ ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
2243
2256
  end
2244
2257
 
2245
2258
  it 'produces a JUnit XML report' do
@@ -2333,10 +2346,13 @@ describe "#{KnapsackPro::Runners::Queue::RSpecRunner} - Integration tests", :cle
2333
2346
  # remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
2334
2347
  # for the following slow test files
2335
2348
  ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"
2349
+
2350
+ ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
2336
2351
  end
2337
2352
  after do
2338
2353
  ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
2339
2354
  ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
2355
+ ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
2340
2356
  end
2341
2357
 
2342
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 },
@@ -2,7 +2,7 @@ describe KnapsackPro::TestCaseMergers::RSpecMerger do
2
2
  describe '#call' do
3
3
  subject { described_class.new(test_files).call }
4
4
 
5
- context 'when all test files are not test example paths' do
5
+ context 'when test files are regular file paths (not test example paths)' do
6
6
  let(:test_files) do
7
7
  [
8
8
  { 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
@@ -10,7 +10,7 @@ describe KnapsackPro::TestCaseMergers::RSpecMerger do
10
10
  ]
11
11
  end
12
12
 
13
- it do
13
+ it 'returns the test files unchanged' do
14
14
  expect(subject).to eq([
15
15
  { 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
16
16
  { 'path' => 'spec/b_spec.rb', 'time_execution' => 2.2 },
@@ -28,7 +28,7 @@ describe KnapsackPro::TestCaseMergers::RSpecMerger do
28
28
  ]
29
29
  end
30
30
 
31
- it 'returns merged paths for test examples and sum of their time_execution' do
31
+ it 'merges the test example paths and sums their execution times' do
32
32
  expect(subject).to eq([
33
33
  { 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
34
34
  { 'path' => 'spec/test_case_spec.rb', 'time_execution' => 3.0 },
@@ -36,23 +36,45 @@ describe KnapsackPro::TestCaseMergers::RSpecMerger do
36
36
  end
37
37
  end
38
38
 
39
- context 'when test files have test example paths and at the same time test file path for test example path is present as full test file path' do
40
- let(:test_files) do
41
- [
42
- { 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
43
- # full test file path is present despite existing test example paths
44
- { 'path' => 'spec/test_case_spec.rb', 'time_execution' => 1.0 },
45
- # test example paths
46
- { 'path' => 'spec/test_case_spec.rb[1:1]', 'time_execution' => 2.2 },
47
- { 'path' => 'spec/test_case_spec.rb[1:2]', 'time_execution' => 0.8 },
48
- ]
39
+ context 'when test files have test example paths and the full test file path exists simultaneously' do
40
+ context 'when the full test file path has a higher execution time than the sum of test example paths' do
41
+ let(:test_files) do
42
+ [
43
+ { 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
44
+ # full test file path exists alongside test example paths
45
+ { 'path' => 'spec/test_case_spec.rb', 'time_execution' => 3.1 },
46
+ # test example paths
47
+ { 'path' => 'spec/test_case_spec.rb[1:1]', 'time_execution' => 2.2 },
48
+ { 'path' => 'spec/test_case_spec.rb[1:2]', 'time_execution' => 0.8 },
49
+ ]
50
+ end
51
+
52
+ it 'returns the full test file path execution time' do
53
+ expect(subject).to eq([
54
+ { 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
55
+ { 'path' => 'spec/test_case_spec.rb', 'time_execution' => 3.1 },
56
+ ])
57
+ end
49
58
  end
50
59
 
51
- it 'returns merged paths for test examples and sum of their time_execution' do
52
- expect(subject).to eq([
53
- { 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
54
- { 'path' => 'spec/test_case_spec.rb', 'time_execution' => 4.0 },
55
- ])
60
+ context 'when the full test file path has a lower execution time than the sum of test example paths' do
61
+ let(:test_files) do
62
+ [
63
+ { 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
64
+ # full test file path exists alongside test example paths
65
+ { 'path' => 'spec/test_case_spec.rb', 'time_execution' => 2.9 },
66
+ # test example paths
67
+ { 'path' => 'spec/test_case_spec.rb[1:1]', 'time_execution' => 2.2 },
68
+ { 'path' => 'spec/test_case_spec.rb[1:2]', 'time_execution' => 0.8 },
69
+ ]
70
+ end
71
+
72
+ it "returns the sum of test example paths' execution times" do
73
+ expect(subject).to eq([
74
+ { 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
75
+ { 'path' => 'spec/test_case_spec.rb', 'time_execution' => 3.0 },
76
+ ])
77
+ end
56
78
  end
57
79
  end
58
80
  end
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.10.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-29 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
@@ -178,6 +178,20 @@ dependencies:
178
178
  - - ">="
179
179
  - !ruby/object:Gem::Version
180
180
  version: 0.9.9
181
+ - !ruby/object:Gem::Dependency
182
+ name: ostruct
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: 0.6.0
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: 0.6.0
181
195
  description: Knapsack Pro wraps your current test runner(s) and works with your existing
182
196
  CI infrastructure to parallelize tests optimally. It dynamically splits your tests
183
197
  based on up-to-date test execution data. It's designed from the ground up for CI