Skip to content

Commit

Permalink
feat: default KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true
Browse files Browse the repository at this point in the history
  • Loading branch information
3v0k4 committed Feb 19, 2025
1 parent 5585ad9 commit 4a6ea88
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 54 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

### Unreleased (Major)

* Enable [`KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES`](https://docs.knapsackpro.com/ruby/split-by-test-examples/) by default
* This should improve the speed of your builds, but you can disable it with [`KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=false`](https://docs.knapsackpro.com/ruby/reference/#knapsack_pro_rspec_split_by_test_examples-rspec)

https://github.com/KnapsackPro/knapsack_pro-ruby/pull/288

### 7.14.0

* Improve debugging for hanging CI nodes: show hanging spec files in the RSpec output and a command to reproduce the current batch of tests.
Expand Down
9 changes: 8 additions & 1 deletion lib/knapsack_pro/config/env.rb
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,14 @@ def cucumber_queue_prefix
def rspec_split_by_test_examples?
return @rspec_split_by_test_examples if defined?(@rspec_split_by_test_examples)

split = ENV.fetch('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES', false).to_s == 'true'
env = ENV['KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES']

if defined?(::Turnip) && env.nil?
KnapsackPro.logger.warn("You have required turnip so SBTE is off. If you don't use turnip you can enable SBTE. Read more: LINK")
return (@rspec_split_by_test_examples = false)
end

split = (env || true).to_s == 'true'

if split && ci_node_total < 2
KnapsackPro.logger.debug('Skipping split of test files by test examples because you are running tests on a single CI node (no parallelism)')
Expand Down
1 change: 1 addition & 0 deletions lib/knapsack_pro/formatters/time_tracker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ def path_for(example)
def rspec_split_by_test_example?(file)
return false unless KnapsackPro::Config::Env.rspec_split_by_test_examples?
return false unless KnapsackPro::Adapters::RSpecAdapter.slow_test_file?(KnapsackPro::Adapters::RSpecAdapter, file)

true
end

Expand Down
15 changes: 0 additions & 15 deletions spec/integration/runners/queue/rspec_runner_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1961,16 +1961,13 @@ def when_first_matching_example_defined(type:)

context 'when the RSpec split by examples is enabled' do
before do
ENV['KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES'] = 'true'

# remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
# for the following slow test files
ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"

ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
end
after do
ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
end
Expand Down Expand Up @@ -2060,16 +2057,13 @@ def when_first_matching_example_defined(type:)

context 'when the RSpec split by examples is enabled AND --tag is set' do
before do
ENV['KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES'] = 'true'

# remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
# for the following slow test files
ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"

ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
end
after do
ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
end
Expand Down Expand Up @@ -2141,16 +2135,13 @@ def when_first_matching_example_defined(type:)
let(:json_file) { "#{SPEC_DIRECTORY}/rspec.json" }

before do
ENV['KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES'] = 'true'

# remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
# for the following slow test files
ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"

ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
end
after do
ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
end
Expand Down Expand Up @@ -2243,16 +2234,13 @@ def when_first_matching_example_defined(type:)
let(:xml_file) { "#{SPEC_DIRECTORY}/rspec.xml" }

before do
ENV['KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES'] = 'true'

# remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
# for the following slow test files
ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"

ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
end
after do
ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
end
Expand Down Expand Up @@ -2343,16 +2331,13 @@ def when_first_matching_example_defined(type:)
let(:coverage_file) { "#{coverage_dir}/index.html" }

before do
ENV['KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES'] = 'true'

# remember to stub Queue API batches to include test examples (example: a_spec.rb[1:1])
# for the following slow test files
ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN'] = "#{SPEC_DIRECTORY}/a_spec.rb"

ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] = '2'
end
after do
ENV.delete('KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES')
ENV.delete('KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN')
ENV.delete('KNAPSACK_PRO_CI_NODE_TOTAL')
end
Expand Down
69 changes: 31 additions & 38 deletions spec/knapsack_pro/config/env_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1014,53 +1014,46 @@
end

describe '.rspec_split_by_test_examples?' do
subject { described_class.rspec_split_by_test_examples? }

after(:each) do
described_class.remove_instance_variable(:@rspec_split_by_test_examples)
end

context 'when KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true AND KNAPSACK_PRO_CI_NODE_TOTAL >= 2' do
before do
stub_const("ENV", { 'KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES' => 'true', 'KNAPSACK_PRO_CI_NODE_TOTAL' => '2' })
expect(KnapsackPro).not_to receive(:logger)
end

it { should be true }
end

context 'when KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=false AND KNAPSACK_PRO_CI_NODE_TOTAL >= 2' do
before do
stub_const("ENV", { 'KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES' => 'false', 'KNAPSACK_PRO_CI_NODE_TOTAL' => '2' })
expect(KnapsackPro).not_to receive(:logger)
end

it { should be false }
end

context 'when KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true AND KNAPSACK_PRO_CI_NODE_TOTAL < 2' do
before { stub_const("ENV", { 'KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES' => 'true', 'KNAPSACK_PRO_CI_NODE_TOTAL' => '1' }) }

it { should be false }
[
[ "false", "2", :turnip, false ],
[ "false", "2", nil, false ],
[ "true", "2", :turnip, true ],
[ "true", "2", nil, true ],
[ nil, "2", :turnip, false, :warn, "You have required turnip so SBTE is off. If you don't use turnip you can enable SBTE. Read more: LINK" ],
[ nil, "2", nil, true ],
[ "false", "1", :turnip, false ],
[ "false", "1", nil, false ],
[ "true", "1", :turnip, false, :debug, "Skipping split of test files by test examples because you are running tests on a single CI node (no parallelism)" ],
[ "true", "1", nil, false, :debug, "Skipping split of test files by test examples because you are running tests on a single CI node (no parallelism)" ],
[ nil, "1", :turnip, false, :warn, "You have required turnip so SBTE is off. If you don't use turnip you can enable SBTE. Read more: LINK" ],
[ nil, "1", nil, false, :debug, "Skipping split of test files by test examples because you are running tests on a single CI node (no parallelism)" ],

].each do |sbte, node_total, turnip, expected, log_level, log_message|
context "KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=#{sbte.inspect} AND KNAPSACK_PRO_CI_NODE_TOTAL=#{node_total.inspect} AND :Turnip is #{turnip ? "defined" : "not defined"}" do
before do
stub_const("ENV", { 'KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES' => sbte, 'KNAPSACK_PRO_CI_NODE_TOTAL' => node_total }.compact)
module Turnip; end if turnip

context 'when called twice' do
it 'logs a debug message only once' do
logger = instance_double(Logger)
expect(KnapsackPro).to receive(:logger).and_return(logger)
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)')
if log_level && log_message
logger = instance_double(Logger)
expect(KnapsackPro).to receive(:logger).and_return(logger)
expect(logger).to receive(log_level).once.with(log_message)
end
end

2.times { described_class.rspec_split_by_test_examples? }
after do
Object.send(:remove_const, :Turnip) if turnip
end
end
end

context "when ENV doesn't exist" do
before do
stub_const("ENV", {})
expect(KnapsackPro).not_to receive(:logger)
it do
expect(described_class.rspec_split_by_test_examples?).to eq(expected)
expect(described_class.rspec_split_by_test_examples?).to eq(expected)
end
end

it { should be false }
end
end

Expand Down

0 comments on commit 4a6ea88

Please sign in to comment.