Add an option threshold: to .parallel() setup method (#42789)

This adds an additional method to configure the parallelization
threshold. Before this, the only way of configuring the threshold was
via an option:

```
config.active_support.test_parallelization_minimum_number_of_tests
```
This commit is contained in:
Jorge Manrubia 2021-07-16 20:32:23 +02:00 committed by GitHub
parent 52e3dc23b9
commit 675d9ffb6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 45 additions and 19 deletions

View File

@ -1,13 +1,23 @@
* Parallelize tests only when overhead is justified by the number of them * Faster tests by parallelizing only when overhead is justified by the number
of them.
Running tests in parallel adds overhead in terms of database Running tests in parallel adds overhead in terms of database
setup and fixture loading. Now, Rails will only parallelize test executions when setup and fixture loading. Now, Rails will only parallelize test executions when
there are enough tests to make it worth it. there are enough tests to make it worth it.
This threshold is 50 by default, and is configurable via: This threshold is 50 by default, and is configurable via config setting in
your test.rb:
```ruby ```ruby
config.active_support.test_parallelization_minimum_number_of_tests = 100 config.active_support.test_parallelization_threshold = 100
```
It's also configurable at the test case level:
```ruby
class ActiveSupport::TestCase
parallelize threshold: 100
end
``` ```
*Jorge Manrubia* *Jorge Manrubia*

View File

@ -88,7 +88,7 @@ module ActiveSupport
cattr_accessor :test_order # :nodoc: cattr_accessor :test_order # :nodoc:
cattr_accessor :test_parallelization_disabled, default: false # :nodoc: cattr_accessor :test_parallelization_disabled, default: false # :nodoc:
cattr_accessor :test_parallelization_minimum_number_of_tests, default: 50 # :nodoc: cattr_accessor :test_parallelization_threshold, default: 50 # :nodoc:
def self.disable_test_parallelization! def self.disable_test_parallelization!
self.test_parallelization_disabled = true unless ENV["PARALLEL_WORKERS"] self.test_parallelization_disabled = true unless ENV["PARALLEL_WORKERS"]

View File

@ -72,13 +72,17 @@ module ActiveSupport
# #
# The threaded parallelization uses minitest's parallel executor directly. # The threaded parallelization uses minitest's parallel executor directly.
# The processes parallelization uses a Ruby DRb server. # The processes parallelization uses a Ruby DRb server.
def parallelize(workers: :number_of_processors, with: :processes) #
# Because parallelization presents an overhead, it is only enabled when the
# number of tests to run is above the +threshold+ param. The default value is
# 50, and it's configurable via +config.active_support.test_parallelization_threshold+.
def parallelize(workers: :number_of_processors, with: :processes, threshold: ActiveSupport.test_parallelization_threshold)
workers = Concurrent.physical_processor_count if workers == :number_of_processors workers = Concurrent.physical_processor_count if workers == :number_of_processors
workers = ENV["PARALLEL_WORKERS"].to_i if ENV["PARALLEL_WORKERS"] workers = ENV["PARALLEL_WORKERS"].to_i if ENV["PARALLEL_WORKERS"]
return if workers <= 1 || ActiveSupport.test_parallelization_disabled return if workers <= 1 || ActiveSupport.test_parallelization_disabled
Minitest.parallel_executor = ActiveSupport::Testing::ParallelizeExecutor.new(size: workers, with: with) Minitest.parallel_executor = ActiveSupport::Testing::ParallelizeExecutor.new(size: workers, with: with, threshold: threshold)
end end
# Set up hook for parallel testing. This can be used if you have multiple # Set up hook for parallel testing. This can be used if you have multiple

View File

@ -3,12 +3,12 @@
module ActiveSupport module ActiveSupport
module Testing module Testing
class ParallelizeExecutor # :nodoc: class ParallelizeExecutor # :nodoc:
attr_reader :size, :parallelize_with, :parallel_executor attr_reader :size, :parallelize_with, :threshold
def initialize(size:, with:) def initialize(size:, with:, threshold: ActiveSupport.test_parallelization_threshold)
@size = size @size = size
@parallelize_with = with @parallelize_with = with
@parallel_executor = build_parallel_executor @threshold = threshold
end end
def start def start
@ -27,6 +27,10 @@ module ActiveSupport
end end
private private
def parallel_executor
@parallel_executor ||= build_parallel_executor
end
def build_parallel_executor def build_parallel_executor
case parallelize_with case parallelize_with
when :processes when :processes
@ -49,7 +53,7 @@ module ActiveSupport
end end
def should_parallelize? def should_parallelize?
ENV["PARALLEL_WORKERS"] || tests_count > ActiveSupport.test_parallelization_minimum_number_of_tests ENV["PARALLEL_WORKERS"] || tests_count > threshold
end end
def tests_count def tests_count
@ -64,7 +68,7 @@ module ActiveSupport
if parallelized? if parallelized?
"Running #{tests_count} tests in parallel using #{parallel_executor.size} #{parallelize_with}" "Running #{tests_count} tests in parallel using #{parallel_executor.size} #{parallelize_with}"
else else
"Running #{tests_count} tests in a single process (parallelization threshold is #{ActiveSupport.test_parallelization_minimum_number_of_tests})" "Running #{tests_count} tests in a single process (parallelization threshold is #{threshold})"
end end
end end
end end

View File

@ -573,10 +573,20 @@ create as changes are not automatically rolled back after the test completes.
Running tests in parallel adds an overhead in terms of database setup and Running tests in parallel adds an overhead in terms of database setup and
fixture loading. Because of this, Rails won't parallelize executions that involve fixture loading. Because of this, Rails won't parallelize executions that involve
fewer than 50 tests. You can configure this threshold in your `test.rb`: fewer than 50 tests.
You can configure this threshold in your `test.rb`:
```ruby ```ruby
config.active_support.test_parallelization_minimum_number_of_tests = 100 config.active_support.test_parallelization_threshold = 100
```
And also when setting up parallelization at the test case level:
```ruby
class ActiveSupport::TestCase
parallelize threshold: 100
end
``` ```
The Test Database The Test Database

View File

@ -2421,18 +2421,18 @@ module ApplicationTests
assert_equal OpenSSL::Digest::SHA256, ActiveSupport::KeyGenerator.hash_digest_class assert_equal OpenSSL::Digest::SHA256, ActiveSupport::KeyGenerator.hash_digest_class
end end
test "ActiveSupport.test_parallelization_minimum_number_of_tests can be configured via config.active_support.test_parallelization_minimum_number_of_tests" do test "ActiveSupport.test_parallelization_threshold can be configured via config.active_support.test_parallelization_threshold" do
remove_from_config '.*config\.load_defaults.*\n' remove_from_config '.*config\.load_defaults.*\n'
app_file "config/environments/test.rb", <<-RUBY app_file "config/environments/test.rb", <<-RUBY
Rails.application.configure do Rails.application.configure do
config.active_support.test_parallelization_minimum_number_of_tests = 1234 config.active_support.test_parallelization_threshold = 1234
end end
RUBY RUBY
app "test" app "test"
assert_equal 1234, ActiveSupport.test_parallelization_minimum_number_of_tests assert_equal 1234, ActiveSupport.test_parallelization_threshold
end end
test "custom serializers should be able to set via config.active_job.custom_serializers in an initializer" do test "custom serializers should be able to set via config.active_job.custom_serializers in an initializer" do

View File

@ -1166,8 +1166,6 @@ module ApplicationTests
require_relative "../config/environment" require_relative "../config/environment"
require "rails/test_help" require "rails/test_help"
ActiveSupport.test_parallelization_minimum_number_of_tests = #{threshold}
class ActiveSupport::TestCase class ActiveSupport::TestCase
<%- if force -%> <%- if force -%>
# Force parallelization, even with single files # Force parallelization, even with single files
@ -1175,7 +1173,7 @@ module ApplicationTests
<%- end -%> <%- end -%>
# Run tests in parallel with specified workers # Run tests in parallel with specified workers
parallelize(workers: 2, with: :<%= with %>) parallelize(workers: 2, with: :<%= with %>, threshold: #{threshold})
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all fixtures :all