Skip to content

Enable Split By Test Example by default in RSpec #288

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 32 commits into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
f4b73bb
chore: sort deps alphabetically
3v0k4 Feb 17, 2025
e9d59e6
chore: improve code comments
3v0k4 Feb 17, 2025
4d221bf
feat: default KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true
3v0k4 Feb 19, 2025
9866da7
tmp: always enable rspec split by test examples
ArturT Feb 21, 2025
57c1f6c
Update config.yml
ArturT Feb 21, 2025
b2bf71a
Update config.yml
ArturT Feb 21, 2025
14e96ee
Update env.rb
ArturT Feb 21, 2025
ce55b56
Update env_spec.rb
ArturT Feb 21, 2025
c6b4503
Update config.yml
ArturT Feb 21, 2025
97dd141
Update CHANGELOG.md
ArturT Feb 21, 2025
e72c161
Update env.rb
ArturT Feb 21, 2025
e6c091d
wip
ArturT Feb 21, 2025
35f0893
Update env_spec.rb
ArturT Feb 21, 2025
cb0ce88
add a test and the remove_formatters method
ArturT Feb 24, 2025
f7b7f38
add missing require set
ArturT Feb 24, 2025
8a68ef0
[WIP] make tags work in queue mode for SBTE
ArturT Feb 24, 2025
52cdf92
Update rspec_test_example_detector_spec.rb
ArturT Feb 24, 2025
fff85aa
Update rspec_runner_spec.rb
ArturT Feb 24, 2025
09d53f9
[wip] add support for tags with SBTE in regular mode
ArturT Feb 24, 2025
1db55ea
add CI test for SBTE + regular/queue mode
ArturT Feb 24, 2025
fe4096c
Update config.yml
ArturT Feb 25, 2025
ae757ea
Update CHANGELOG.md
ArturT Feb 25, 2025
7444900
Apply suggestions from code review
ArturT Feb 25, 2025
3a0130f
use rspec_args in spec
ArturT Feb 25, 2025
5ddabc5
rename expected_args
ArturT Feb 25, 2025
dd065ee
don't use Set.new
ArturT Feb 25, 2025
ffc2d90
add a comment about rspec behaviour
ArturT Feb 25, 2025
63d12c4
Update rspec_runner_spec.rb
ArturT Feb 25, 2025
c64b1b4
fix typo
ArturT Feb 25, 2025
ae8be1b
raise an exception if KNAPSACK_PRO_RSPEC_OPTIONS is accidentally over…
ArturT Feb 25, 2025
bc5727f
remove @ from tags
ArturT Feb 25, 2025
fd1389a
ensure cli_args are not mutated
ArturT Feb 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,15 @@ jobs:
export KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true
export KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN="spec/features/calculator_spec.rb"
bundle exec rake knapsack_pro:rspec
- run:
working_directory: ~/rails-app-with-knapsack_pro
command: |
# split custom files by test examples AND the --tag option passed ||
export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--$CIRCLE_BUILD_NUM--regular--split-custom-files--tag-option"
export KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true
export KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN="spec/bar_spec.rb"
export SKIP_ME_OR_I_WILL_FAIL=true
bundle exec rake "knapsack_pro:rspec[--tag tag_x -t ~tag_y --tag ~skip_me_or_i_will_fail --format documentation]"

e2e-queue-rspec:
parameters:
Expand Down Expand Up @@ -289,24 +298,47 @@ jobs:
export KNAPSACK_PRO_CI_NODE_TOTAL=1
export KNAPSACK_PRO_CI_NODE_INDEX=0
bundle exec rake knapsack_pro:queue:rspec
- run:
working_directory: ~/rails-app-with-knapsack_pro
command: |
# split custom files by test examples AND the --tag option passed ||
export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--$CIRCLE_BUILD_NUM--queue--split-custom-files--tag-option"
export KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true
export KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN="spec/bar_spec.rb"
export SKIP_ME_OR_I_WILL_FAIL=true
bundle exec rake "knapsack_pro:queue:rspec[--tag tag_x -t ~tag_y --tag ~skip_me_or_i_will_fail --format documentation]"
- run:
working_directory: ~/rails-app-with-knapsack_pro
command: |
# turnip ||
mv .rspec .rspec.off
cp .rspec.turnip .rspec
export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--$CIRCLE_BUILD_NUM--queue--turnip"
export KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true
export KNAPSACK_PRO_TEST_DIR=turnip
export KNAPSACK_PRO_TEST_FILE_PATTERN="turnip/**/*.feature"
bundle exec rake "knapsack_pro:queue:rspec[-r turnip/rspec]"
export KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN="turnip/acceptance/foo.feature"
bundle exec rake knapsack_pro:queue:rspec
RSPEC_EXIT_CODE=$?
rm .rspec
mv .rspec.off .rspec
exit $RSPEC_EXIT_CODE
- run:
working_directory: ~/rails-app-with-knapsack_pro
command: |
# turnip retry ||
mv .rspec .rspec.off
cp .rspec.turnip .rspec
export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--$CIRCLE_BUILD_NUM--queue--turnip"
export KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true
export KNAPSACK_PRO_TEST_DIR=turnip
export KNAPSACK_PRO_TEST_FILE_PATTERN="turnip/**/*.feature"
bundle exec rake "knapsack_pro:queue:rspec[-r turnip/rspec]"
export KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN="turnip/acceptance/foo.feature"
bundle exec rake knapsack_pro:queue:rspec
RSPEC_EXIT_CODE=$?
rm .rspec
mv .rspec.off .rspec
exit $RSPEC_EXIT_CODE

e2e-regular-minitest:
parallelism: 2
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog

### 8.0.0

* 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)
* Support RSpec tags when using [RSpec split by examples](https://docs.knapsackpro.com/ruby/split-by-test-examples/).

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

https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v7.14.1...v8.0.0

### 7.14.1

* Improve execution time tracking for RSpec individual test examples
Expand Down
10 changes: 5 additions & 5 deletions knapsack_pro.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ Gem::Specification.new do |spec|
spec.add_dependency 'rake', '>= 0'

spec.add_development_dependency 'bundler', '>= 1.6'
spec.add_development_dependency 'cucumber', '>= 0'
spec.add_development_dependency 'minitest', '>= 5.0.0'
spec.add_development_dependency 'ostruct', '>= 0.6.0'
spec.add_development_dependency 'pry', '~> 0'
spec.add_development_dependency 'rspec', '~> 3.0'
spec.add_development_dependency 'rspec-its', '~> 1.3'
spec.add_development_dependency 'cucumber', '>= 0'
spec.add_development_dependency 'spinach', '>= 0.8'
spec.add_development_dependency 'minitest', '>= 5.0.0'
spec.add_development_dependency 'test-unit', '>= 3.0.0'
spec.add_development_dependency 'pry', '~> 0'
spec.add_development_dependency 'timecop', '>= 0.9.9'
spec.add_development_dependency 'vcr', '>= 6.0'
spec.add_development_dependency 'webmock', '>= 3.13'
spec.add_development_dependency 'timecop', '>= 0.9.9'
spec.add_development_dependency 'ostruct', '>= 0.6.0'
end
23 changes: 11 additions & 12 deletions lib/knapsack_pro/adapters/rspec_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,6 @@ def self.test_file_cases_for(slow_test_files)
KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector.new.test_file_example_paths
end

def self.ensure_no_tag_option_when_rspec_split_by_test_examples_enabled!(cli_args)
if KnapsackPro::Config::Env.rspec_split_by_test_examples? && has_tag_option?(cli_args)
error_message = "It is not allowed to use the RSpec tag option together with the RSpec split by test examples feature. Please see: #{KnapsackPro::Urls::RSPEC__SPLIT_BY_TEST_EXAMPLES__TAG}"
KnapsackPro.logger.error(error_message)
raise error_message
end
end

def self.has_tag_option?(cli_args)
!!parsed_options(cli_args)&.[](:inclusion_filter)
end

def self.has_format_option?(cli_args)
!!parsed_options(cli_args)&.[](:formatters)
end
Expand All @@ -61,6 +49,17 @@ def self.order_option(cli_args)
parsed_options(cli_args)&.[](:order)
end

def self.remove_formatters(cli_args)
formatter_options = ['-f', '--format', '-o', '--out']
cli_args.dup.each_with_index do |arg, index|
if formatter_options.include?(arg)
cli_args[index] = nil
cli_args[index + 1] = nil
end
end
cli_args.compact
end

def self.file_path_for(example)
[
-> { parse_file_path(example.id) },
Expand Down
10 changes: 5 additions & 5 deletions lib/knapsack_pro/base_allocator_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ def test_dir
KnapsackPro::Config::Env.test_dir || TestFilePattern.test_dir(adapter_class)
end

# in fallback mode we always want to run the whole test files
# (not split by test cases) to guarantee that each test will be executed
# at least once across parallel CI nodes
# In Fallback Mode, we always want to run whole test files (not split by
# test cases) to guarantee that each test will be executed at least once
# across parallel CI nodes.
def fallback_mode_test_files
all_test_files_to_run
end

# detect test files present on the disk that should be run
# this may include some fast test files + slow test files split by test cases
# Detect test files present on the disk that should be run.
# This may include fast test files + slow test files split by test cases.
def fast_and_slow_test_files_to_run
test_files_to_run = all_test_files_to_run

Expand Down
11 changes: 9 additions & 2 deletions lib/knapsack_pro/config/env.rb
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,17 @@ 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 test_files_encrypted? && env.nil?
KnapsackPro.logger.warn("Skipping split by test examples because test file names encryption is enabled:\n#{KnapsackPro::Urls::ENCRYPTION}\n#{KnapsackPro::Urls::SPLIT_BY_TEST_EXAMPLES}")
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)')
KnapsackPro.logger.debug('Skipping split by test examples because tests are running on a single CI node (no parallelism)')
@rspec_split_by_test_examples = false
else
@rspec_split_by_test_examples = split
Expand Down
2 changes: 1 addition & 1 deletion lib/knapsack_pro/runners/queue/rspec_runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def self.run(args, stream_error = $stderr, stream_out = $stdout)
end

def initialize(adapter_class, rspec_pure, args, stream_error, stream_out)
ENV['KNAPSACK_PRO_RSPEC_OPTIONS'] = args.to_s
super(adapter_class)
@adapter_class = adapter_class
@rspec_pure = rspec_pure
Expand Down Expand Up @@ -149,7 +150,6 @@ def pre_run_setup
KnapsackPro::Config::Env.set_test_runner_adapter(@adapter_class)

ENV['SPEC_OPTS'] = @rspec_pure.add_knapsack_pro_formatters_to(ENV['SPEC_OPTS'])
@adapter_class.ensure_no_tag_option_when_rspec_split_by_test_examples_enabled!(@cli_args)

rspec_configuration_options = ::RSpec::Core::ConfigurationOptions.new(@cli_args)
@rspec_runner = ::RSpec::Core::Runner.new(rspec_configuration_options)
Expand Down
4 changes: 1 addition & 3 deletions lib/knapsack_pro/runners/rspec_runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ def self.run(args)

ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN'] = KnapsackPro::Config::Env.test_suite_token_rspec
ENV['KNAPSACK_PRO_REGULAR_MODE_ENABLED'] = 'true'
ENV['KNAPSACK_PRO_RSPEC_OPTIONS'] = args.to_s

adapter_class = KnapsackPro::Adapters::RSpecAdapter
KnapsackPro::Config::Env.set_test_runner_adapter(adapter_class)
Expand All @@ -16,9 +17,6 @@ def self.run(args)
if runner.test_files_to_execute_exist?
adapter_class.verify_bind_method_called

cli_args = (args || '').split
adapter_class.ensure_no_tag_option_when_rspec_split_by_test_examples_enabled!(cli_args)

require 'rspec/core/rake_task'

task_name = 'knapsack_pro:rspec_run'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
module KnapsackPro
module TestCaseDetectors
class RSpecTestExampleDetector
def generate_json_report
def generate_json_report(rspec_args)
raise "The internal KNAPSACK_PRO_RSPEC_OPTIONS environment variable is unset. Ensure it is not overridden accidentally. Otherwise, please report this as a bug: #{KnapsackPro::Urls::SUPPORT}" if rspec_args.nil?

require 'rspec/core'

cli_format =
Expand All @@ -25,7 +27,11 @@ def generate_json_report
return
end

cli_args = cli_format + [
args = (rspec_args || '').split
cli_args_without_formatters = KnapsackPro::Adapters::RSpecAdapter.remove_formatters(args)

# Apply a --format option which overrides formatters from the RSpec custom option files like `.rspec`.
cli_args = cli_args_without_formatters + cli_format + [
'--dry-run',
'--no-color',
'--out', report_path,
Expand Down
2 changes: 1 addition & 1 deletion lib/knapsack_pro/tracker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def save_prerun_tests_report(hash)
end

def read_prerun_tests_report
raise "Report #{prerun_tests_report_path} doest not exist on the disk. Most likely, it was removed accidentally. Please report the bug to the Knapsack Pro support team at #{KnapsackPro::Urls::SUPPORT}" unless File.exist?(prerun_tests_report_path)
raise "Report #{prerun_tests_report_path} does not exist on the disk. Most likely, it was removed accidentally. Please report the bug to the Knapsack Pro support team at #{KnapsackPro::Urls::SUPPORT}" unless File.exist?(prerun_tests_report_path)
JSON.parse(File.read(prerun_tests_report_path))
end

Expand Down
2 changes: 0 additions & 2 deletions lib/knapsack_pro/urls.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ module Urls

RSPEC__SKIPS_TESTS = "#{HOST}/perma/ruby/rspec-skips-tests"

RSPEC__SPLIT_BY_TEST_EXAMPLES__TAG = "#{HOST}/perma/ruby/rspec-split-by-test-examples-tag"

SPLIT_BY_TEST_EXAMPLES = "#{HOST}/perma/ruby/split-by-test-examples"

TEST_UNIT__TEST_FILE_PATH_DETECTION = "#{HOST}/perma/ruby/test-unit-test-file-path-detection"
Expand Down
2 changes: 1 addition & 1 deletion lib/tasks/rspec.rake
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ namespace :knapsack_pro do
ENV.delete('SPEC_OPTS')

detector = KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector.new
detector.generate_json_report
detector.generate_json_report(ENV['KNAPSACK_PRO_RSPEC_OPTIONS'])
end
end
Loading