activesupport 6.0.6.1 → 7.1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +865 -438
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -6
- data/lib/active_support/actionable_error.rb +4 -2
- data/lib/active_support/array_inquirer.rb +4 -2
- data/lib/active_support/backtrace_cleaner.rb +30 -10
- data/lib/active_support/benchmarkable.rb +4 -3
- data/lib/active_support/broadcast_logger.rb +250 -0
- data/lib/active_support/builder.rb +1 -1
- data/lib/active_support/cache/coder.rb +153 -0
- data/lib/active_support/cache/entry.rb +134 -0
- data/lib/active_support/cache/file_store.rb +53 -20
- data/lib/active_support/cache/mem_cache_store.rb +208 -63
- data/lib/active_support/cache/memory_store.rb +120 -38
- data/lib/active_support/cache/null_store.rb +16 -2
- data/lib/active_support/cache/redis_cache_store.rb +201 -208
- data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
- data/lib/active_support/cache/strategy/local_cache.rb +73 -66
- data/lib/active_support/cache.rb +539 -261
- data/lib/active_support/callbacks.rb +273 -142
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +53 -7
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +44 -7
- data/lib/active_support/concurrency/null_lock.rb +13 -0
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +19 -6
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +15 -13
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/array/inquiry.rb +2 -2
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +34 -44
- data/lib/active_support/core_ext/class/subclasses.rb +19 -29
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +24 -9
- data/lib/active_support/core_ext/date/conversions.rb +18 -16
- data/lib/active_support/core_ext/date_and_time/calculations.rb +27 -4
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +19 -15
- data/lib/active_support/core_ext/digest/uuid.rb +30 -13
- data/lib/active_support/core_ext/enumerable.rb +146 -72
- data/lib/active_support/core_ext/erb/util.rb +196 -0
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +3 -4
- data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +4 -4
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +5 -5
- data/lib/active_support/core_ext/hash/slice.rb +3 -2
- data/lib/active_support/core_ext/integer/inflections.rb +12 -12
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +31 -29
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +51 -20
- data/lib/active_support/core_ext/module/concerning.rb +14 -8
- data/lib/active_support/core_ext/module/delegation.rb +75 -42
- data/lib/active_support/core_ext/module/deprecation.rb +15 -12
- data/lib/active_support/core_ext/module/introspection.rb +1 -26
- data/lib/active_support/core_ext/name_error.rb +23 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +82 -73
- data/lib/active_support/core_ext/object/acts_like.rb +29 -5
- data/lib/active_support/core_ext/object/blank.rb +2 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +17 -1
- data/lib/active_support/core_ext/object/duplicable.rb +15 -4
- data/lib/active_support/core_ext/object/inclusion.rb +13 -5
- data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
- data/lib/active_support/core_ext/object/json.rb +52 -28
- data/lib/active_support/core_ext/object/to_query.rb +2 -4
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/object/with.rb +44 -0
- data/lib/active_support/core_ext/object/with_options.rb +25 -6
- data/lib/active_support/core_ext/object.rb +1 -0
- data/lib/active_support/core_ext/pathname/blank.rb +16 -0
- data/lib/active_support/core_ext/pathname/existence.rb +23 -0
- data/lib/active_support/core_ext/pathname.rb +4 -0
- data/lib/active_support/core_ext/range/compare_range.rb +6 -25
- data/lib/active_support/core_ext/range/conversions.rb +34 -13
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/overlap.rb +40 -0
- data/lib/active_support/core_ext/range.rb +1 -2
- data/lib/active_support/core_ext/regexp.rb +8 -1
- data/lib/active_support/core_ext/securerandom.rb +25 -13
- data/lib/active_support/core_ext/string/access.rb +5 -24
- data/lib/active_support/core_ext/string/conversions.rb +3 -2
- data/lib/active_support/core_ext/string/filters.rb +21 -15
- data/lib/active_support/core_ext/string/indent.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +51 -10
- data/lib/active_support/core_ext/string/inquiry.rb +2 -1
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/string/output_safety.rb +85 -194
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
- data/lib/active_support/core_ext/time/calculations.rb +46 -8
- data/lib/active_support/core_ext/time/conversions.rb +16 -13
- data/lib/active_support/core_ext/time/zones.rb +12 -28
- data/lib/active_support/core_ext.rb +2 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +54 -22
- data/lib/active_support/deep_mergeable.rb +53 -0
- data/lib/active_support/dependencies/autoload.rb +17 -12
- data/lib/active_support/dependencies/interlock.rb +10 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +58 -769
- data/lib/active_support/deprecation/behaviors.rb +77 -38
- data/lib/active_support/deprecation/constant_accessor.rb +5 -4
- data/lib/active_support/deprecation/deprecators.rb +104 -0
- data/lib/active_support/deprecation/disallowed.rb +54 -0
- data/lib/active_support/deprecation/instance_delegator.rb +31 -5
- data/lib/active_support/deprecation/method_wrappers.rb +12 -28
- data/lib/active_support/deprecation/proxy_wrappers.rb +40 -25
- data/lib/active_support/deprecation/reporting.rb +76 -16
- data/lib/active_support/deprecation.rb +36 -4
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +150 -68
- data/lib/active_support/digest.rb +5 -3
- data/lib/active_support/duration/iso8601_parser.rb +3 -3
- data/lib/active_support/duration/iso8601_serializer.rb +24 -12
- data/lib/active_support/duration.rb +136 -56
- data/lib/active_support/encrypted_configuration.rb +72 -9
- data/lib/active_support/encrypted_file.rb +46 -13
- data/lib/active_support/environment_inquirer.rb +40 -0
- data/lib/active_support/error_reporter/test_helper.rb +15 -0
- data/lib/active_support/error_reporter.rb +203 -0
- data/lib/active_support/evented_file_update_checker.rb +86 -137
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +31 -12
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/file_update_checker.rb +4 -2
- data/lib/active_support/fork_tracker.rb +79 -0
- data/lib/active_support/gem_version.rb +5 -5
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +86 -42
- data/lib/active_support/html_safe_translation.rb +53 -0
- data/lib/active_support/i18n.rb +2 -1
- data/lib/active_support/i18n_railtie.rb +29 -27
- data/lib/active_support/inflector/inflections.rb +26 -9
- data/lib/active_support/inflector/methods.rb +54 -64
- data/lib/active_support/inflector/transliterate.rb +7 -5
- data/lib/active_support/isolated_execution_state.rb +76 -0
- data/lib/active_support/json/decoding.rb +6 -5
- data/lib/active_support/json/encoding.rb +31 -45
- data/lib/active_support/key_generator.rb +32 -7
- data/lib/active_support/lazy_load_hooks.rb +33 -7
- data/lib/active_support/locale/en.yml +10 -4
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +101 -32
- data/lib/active_support/logger.rb +9 -60
- data/lib/active_support/logger_silence.rb +2 -26
- data/lib/active_support/logger_thread_safe_level.rb +24 -25
- data/lib/active_support/message_encryptor.rb +205 -58
- data/lib/active_support/message_encryptors.rb +141 -0
- data/lib/active_support/message_pack/cache_serializer.rb +23 -0
- data/lib/active_support/message_pack/extensions.rb +292 -0
- data/lib/active_support/message_pack/serializer.rb +63 -0
- data/lib/active_support/message_pack.rb +50 -0
- data/lib/active_support/message_verifier.rb +237 -86
- data/lib/active_support/message_verifiers.rb +135 -0
- data/lib/active_support/messages/codec.rb +65 -0
- data/lib/active_support/messages/metadata.rb +112 -46
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotation_coordinator.rb +93 -0
- data/lib/active_support/messages/rotator.rb +35 -32
- data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
- data/lib/active_support/multibyte/chars.rb +15 -52
- data/lib/active_support/multibyte/unicode.rb +8 -122
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +310 -105
- data/lib/active_support/notifications/instrumenter.rb +113 -48
- data/lib/active_support/notifications.rb +56 -29
- data/lib/active_support/number_helper/number_converter.rb +15 -8
- data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +5 -5
- data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
- data/lib/active_support/number_helper/rounding_helper.rb +12 -32
- data/lib/active_support/number_helper.rb +379 -304
- data/lib/active_support/option_merger.rb +11 -18
- data/lib/active_support/ordered_hash.rb +4 -4
- data/lib/active_support/ordered_options.rb +23 -3
- data/lib/active_support/parameter_filter.rb +104 -75
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +90 -6
- data/lib/active_support/reloader.rb +12 -4
- data/lib/active_support/rescuable.rb +18 -16
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +58 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +5 -3
- data/lib/active_support/subscriber.rb +23 -47
- data/lib/active_support/syntax_error_proxy.rb +70 -0
- data/lib/active_support/tagged_logging.rb +84 -23
- data/lib/active_support/test_case.rb +166 -27
- data/lib/active_support/testing/assertions.rb +73 -20
- data/lib/active_support/testing/autorun.rb +0 -2
- data/lib/active_support/testing/constant_stubbing.rb +32 -0
- data/lib/active_support/testing/deprecation.rb +53 -2
- data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
- data/lib/active_support/testing/isolation.rb +30 -29
- data/lib/active_support/testing/method_call_assertions.rb +24 -11
- data/lib/active_support/testing/parallelization/server.rb +82 -0
- data/lib/active_support/testing/parallelization/worker.rb +103 -0
- data/lib/active_support/testing/parallelization.rb +16 -95
- data/lib/active_support/testing/parallelize_executor.rb +81 -0
- data/lib/active_support/testing/stream.rb +4 -6
- data/lib/active_support/testing/strict_warnings.rb +39 -0
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +89 -19
- data/lib/active_support/time_with_zone.rb +105 -70
- data/lib/active_support/values/time_zone.rb +59 -26
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +4 -11
- data/lib/active_support/xml_mini/libxml.rb +5 -5
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
- data/lib/active_support/xml_mini/nokogiri.rb +5 -5
- data/lib/active_support/xml_mini/nokogirisax.rb +2 -2
- data/lib/active_support/xml_mini/rexml.rb +9 -2
- data/lib/active_support/xml_mini.rb +7 -6
- data/lib/active_support.rb +40 -1
- metadata +127 -40
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
- data/lib/active_support/core_ext/hash/compact.rb +0 -5
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
- data/lib/active_support/core_ext/marshal.rb +0 -24
- data/lib/active_support/core_ext/module/reachable.rb +0 -6
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
- data/lib/active_support/core_ext/range/include_range.rb +0 -9
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -23
- data/lib/active_support/core_ext/range/overlaps.rb +0 -10
- data/lib/active_support/core_ext/uri.rb +0 -25
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
- data/lib/active_support/per_thread_registry.rb +0 -60
@@ -5,7 +5,7 @@ module ActiveSupport
|
|
5
5
|
module Isolation
|
6
6
|
require "thread"
|
7
7
|
|
8
|
-
def self.included(klass)
|
8
|
+
def self.included(klass) # :nodoc:
|
9
9
|
klass.class_eval do
|
10
10
|
parallelize_me!
|
11
11
|
end
|
@@ -25,45 +25,46 @@ module ActiveSupport
|
|
25
25
|
|
26
26
|
module Forking
|
27
27
|
def run_in_isolation(&blk)
|
28
|
-
read, write
|
29
|
-
|
30
|
-
|
28
|
+
IO.pipe do |read, write|
|
29
|
+
read.binmode
|
30
|
+
write.binmode
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
32
|
+
pid = fork do
|
33
|
+
read.close
|
34
|
+
yield
|
35
|
+
begin
|
36
|
+
if error?
|
37
|
+
failures.map! { |e|
|
38
|
+
begin
|
39
|
+
Marshal.dump e
|
40
|
+
e
|
41
|
+
rescue TypeError
|
42
|
+
ex = Exception.new e.message
|
43
|
+
ex.set_backtrace e.backtrace
|
44
|
+
Minitest::UnexpectedError.new ex
|
45
|
+
end
|
46
|
+
}
|
47
|
+
end
|
48
|
+
test_result = defined?(Minitest::Result) ? Minitest::Result.from(self) : dup
|
49
|
+
result = Marshal.dump(test_result)
|
47
50
|
end
|
48
|
-
|
49
|
-
result
|
51
|
+
|
52
|
+
write.puts [result].pack("m")
|
53
|
+
exit!
|
50
54
|
end
|
51
55
|
|
52
|
-
write.
|
53
|
-
|
56
|
+
write.close
|
57
|
+
result = read.read
|
58
|
+
Process.wait2(pid)
|
59
|
+
result.unpack1("m")
|
54
60
|
end
|
55
|
-
|
56
|
-
write.close
|
57
|
-
result = read.read
|
58
|
-
Process.wait2(pid)
|
59
|
-
result.unpack1("m")
|
60
61
|
end
|
61
62
|
end
|
62
63
|
|
63
64
|
module Subprocess
|
64
65
|
ORIG_ARGV = ARGV.dup unless defined?(ORIG_ARGV)
|
65
66
|
|
66
|
-
#
|
67
|
+
# Complicated H4X to get this working in Windows / JRuby with
|
67
68
|
# no forking.
|
68
69
|
def run_in_isolation(&blk)
|
69
70
|
require "tempfile"
|
@@ -6,10 +6,10 @@ module ActiveSupport
|
|
6
6
|
module Testing
|
7
7
|
module MethodCallAssertions # :nodoc:
|
8
8
|
private
|
9
|
-
def assert_called(object, method_name, message = nil, times: 1, returns: nil)
|
9
|
+
def assert_called(object, method_name, message = nil, times: 1, returns: nil, &block)
|
10
10
|
times_called = 0
|
11
11
|
|
12
|
-
object.stub(method_name, proc { times_called += 1; returns })
|
12
|
+
object.stub(method_name, proc { times_called += 1; returns }, &block)
|
13
13
|
|
14
14
|
error = "Expected #{method_name} to be called #{times} times, " \
|
15
15
|
"but was called #{times_called} times"
|
@@ -17,24 +17,37 @@ module ActiveSupport
|
|
17
17
|
assert_equal times, times_called, error
|
18
18
|
end
|
19
19
|
|
20
|
-
def assert_called_with(object, method_name, args, returns:
|
20
|
+
def assert_called_with(object, method_name, args, returns: false, **kwargs, &block)
|
21
21
|
mock = Minitest::Mock.new
|
22
|
+
expect_called_with(mock, args, returns: returns, **kwargs)
|
22
23
|
|
23
|
-
|
24
|
-
args.each { |arg| mock.expect(:call, returns, arg) }
|
25
|
-
else
|
26
|
-
mock.expect(:call, returns, args)
|
27
|
-
end
|
28
|
-
|
29
|
-
object.stub(method_name, mock) { yield }
|
24
|
+
object.stub(method_name, mock, &block)
|
30
25
|
|
31
|
-
mock
|
26
|
+
assert_mock(mock)
|
32
27
|
end
|
33
28
|
|
34
29
|
def assert_not_called(object, method_name, message = nil, &block)
|
35
30
|
assert_called(object, method_name, message, times: 0, &block)
|
36
31
|
end
|
37
32
|
|
33
|
+
#--
|
34
|
+
# This method is a temporary wrapper for mock.expect as part of
|
35
|
+
# the Minitest 5.16 / Ruby 3.0 kwargs transition. It can go away
|
36
|
+
# when we drop support for Ruby 2.7.
|
37
|
+
if Minitest::Mock.instance_method(:expect).parameters.map(&:first).include?(:keyrest)
|
38
|
+
def expect_called_with(mock, args, returns: false, **kwargs)
|
39
|
+
mock.expect(:call, returns, args, **kwargs)
|
40
|
+
end
|
41
|
+
else
|
42
|
+
def expect_called_with(mock, args, returns: false, **kwargs)
|
43
|
+
if !kwargs.empty?
|
44
|
+
mock.expect(:call, returns, [*args, kwargs])
|
45
|
+
else
|
46
|
+
mock.expect(:call, returns, args)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
38
51
|
def assert_called_on_instance_of(klass, method_name, message = nil, times: 1, returns: nil)
|
39
52
|
times_called = 0
|
40
53
|
klass.define_method("stubbed_#{method_name}") do |*|
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "drb"
|
4
|
+
require "drb/unix" unless Gem.win_platform?
|
5
|
+
|
6
|
+
module ActiveSupport
|
7
|
+
module Testing
|
8
|
+
class Parallelization # :nodoc:
|
9
|
+
class Server
|
10
|
+
include DRb::DRbUndumped
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@queue = Queue.new
|
14
|
+
@active_workers = Concurrent::Map.new
|
15
|
+
@in_flight = Concurrent::Map.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def record(reporter, result)
|
19
|
+
raise DRb::DRbConnError if result.is_a?(DRb::DRbUnknown)
|
20
|
+
|
21
|
+
@in_flight.delete([result.klass, result.name])
|
22
|
+
|
23
|
+
reporter.synchronize do
|
24
|
+
reporter.record(result)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def <<(o)
|
29
|
+
o[2] = DRbObject.new(o[2]) if o
|
30
|
+
@queue << o
|
31
|
+
end
|
32
|
+
|
33
|
+
def pop
|
34
|
+
if test = @queue.pop
|
35
|
+
@in_flight[[test[0].to_s, test[1]]] = test
|
36
|
+
test
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def start_worker(worker_id)
|
41
|
+
@active_workers[worker_id] = true
|
42
|
+
end
|
43
|
+
|
44
|
+
def stop_worker(worker_id)
|
45
|
+
@active_workers.delete(worker_id)
|
46
|
+
end
|
47
|
+
|
48
|
+
def active_workers?
|
49
|
+
@active_workers.size > 0
|
50
|
+
end
|
51
|
+
|
52
|
+
def interrupt
|
53
|
+
@queue.clear
|
54
|
+
end
|
55
|
+
|
56
|
+
def shutdown
|
57
|
+
# Wait for initial queue to drain
|
58
|
+
while @queue.length != 0
|
59
|
+
sleep 0.1
|
60
|
+
end
|
61
|
+
|
62
|
+
@queue.close
|
63
|
+
|
64
|
+
# Wait until all workers have finished
|
65
|
+
while active_workers?
|
66
|
+
sleep 0.1
|
67
|
+
end
|
68
|
+
|
69
|
+
@in_flight.values.each do |(klass, name, reporter)|
|
70
|
+
result = Minitest::Result.from(klass.new(name))
|
71
|
+
error = RuntimeError.new("result not reported")
|
72
|
+
error.set_backtrace([""])
|
73
|
+
result.failures << Minitest::UnexpectedError.new(error)
|
74
|
+
reporter.synchronize do
|
75
|
+
reporter.record(result)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
module Testing
|
5
|
+
class Parallelization # :nodoc:
|
6
|
+
class Worker
|
7
|
+
def initialize(number, url)
|
8
|
+
@id = SecureRandom.uuid
|
9
|
+
@number = number
|
10
|
+
@url = url
|
11
|
+
@setup_exception = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def start
|
15
|
+
fork do
|
16
|
+
set_process_title("(starting)")
|
17
|
+
|
18
|
+
DRb.stop_service
|
19
|
+
|
20
|
+
@queue = DRbObject.new_with_uri(@url)
|
21
|
+
@queue.start_worker(@id)
|
22
|
+
|
23
|
+
begin
|
24
|
+
after_fork
|
25
|
+
rescue => @setup_exception; end
|
26
|
+
|
27
|
+
work_from_queue
|
28
|
+
ensure
|
29
|
+
set_process_title("(stopping)")
|
30
|
+
|
31
|
+
run_cleanup
|
32
|
+
@queue.stop_worker(@id)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def work_from_queue
|
37
|
+
while job = @queue.pop
|
38
|
+
perform_job(job)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def perform_job(job)
|
43
|
+
klass = job[0]
|
44
|
+
method = job[1]
|
45
|
+
reporter = job[2]
|
46
|
+
|
47
|
+
set_process_title("#{klass}##{method}")
|
48
|
+
|
49
|
+
result = klass.with_info_handler reporter do
|
50
|
+
Minitest.run_one_method(klass, method)
|
51
|
+
end
|
52
|
+
|
53
|
+
safe_record(reporter, result)
|
54
|
+
end
|
55
|
+
|
56
|
+
def safe_record(reporter, result)
|
57
|
+
add_setup_exception(result) if @setup_exception
|
58
|
+
|
59
|
+
begin
|
60
|
+
@queue.record(reporter, result)
|
61
|
+
rescue DRb::DRbConnError
|
62
|
+
result.failures.map! do |failure|
|
63
|
+
if failure.respond_to?(:error)
|
64
|
+
# minitest >5.14.0
|
65
|
+
error = DRb::DRbRemoteError.new(failure.error)
|
66
|
+
else
|
67
|
+
error = DRb::DRbRemoteError.new(failure.exception)
|
68
|
+
end
|
69
|
+
Minitest::UnexpectedError.new(error)
|
70
|
+
end
|
71
|
+
@queue.record(reporter, result)
|
72
|
+
rescue Interrupt
|
73
|
+
@queue.interrupt
|
74
|
+
raise
|
75
|
+
end
|
76
|
+
|
77
|
+
set_process_title("(idle)")
|
78
|
+
end
|
79
|
+
|
80
|
+
def after_fork
|
81
|
+
Parallelization.after_fork_hooks.each do |cb|
|
82
|
+
cb.call(@number)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def run_cleanup
|
87
|
+
Parallelization.run_cleanup_hooks.each do |cb|
|
88
|
+
cb.call(@number)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
def add_setup_exception(result)
|
94
|
+
result.failures.prepend Minitest::UnexpectedError.new(@setup_exception)
|
95
|
+
end
|
96
|
+
|
97
|
+
def set_process_title(status)
|
98
|
+
Process.setproctitle("Rails test worker #{@number} - #{status}")
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -3,37 +3,12 @@
|
|
3
3
|
require "drb"
|
4
4
|
require "drb/unix" unless Gem.win_platform?
|
5
5
|
require "active_support/core_ext/module/attribute_accessors"
|
6
|
+
require "active_support/testing/parallelization/server"
|
7
|
+
require "active_support/testing/parallelization/worker"
|
6
8
|
|
7
9
|
module ActiveSupport
|
8
10
|
module Testing
|
9
11
|
class Parallelization # :nodoc:
|
10
|
-
class Server
|
11
|
-
include DRb::DRbUndumped
|
12
|
-
|
13
|
-
def initialize
|
14
|
-
@queue = Queue.new
|
15
|
-
end
|
16
|
-
|
17
|
-
def record(reporter, result)
|
18
|
-
raise DRb::DRbConnError if result.is_a?(DRb::DRbUnknown)
|
19
|
-
|
20
|
-
reporter.synchronize do
|
21
|
-
reporter.record(result)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def <<(o)
|
26
|
-
o[2] = DRbObject.new(o[2]) if o
|
27
|
-
@queue << o
|
28
|
-
end
|
29
|
-
|
30
|
-
def length
|
31
|
-
@queue.length
|
32
|
-
end
|
33
|
-
|
34
|
-
def pop; @queue.pop; end
|
35
|
-
end
|
36
|
-
|
37
12
|
@@after_fork_hooks = []
|
38
13
|
|
39
14
|
def self.after_fork_hook(&blk)
|
@@ -50,85 +25,31 @@ module ActiveSupport
|
|
50
25
|
|
51
26
|
cattr_reader :run_cleanup_hooks
|
52
27
|
|
53
|
-
def initialize(
|
54
|
-
@
|
55
|
-
@
|
56
|
-
@
|
57
|
-
|
58
|
-
@url = DRb.start_service("drbunix:", @queue).uri
|
59
|
-
end
|
60
|
-
|
61
|
-
def after_fork(worker)
|
62
|
-
self.class.after_fork_hooks.each do |cb|
|
63
|
-
cb.call(worker)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def run_cleanup(worker)
|
68
|
-
self.class.run_cleanup_hooks.each do |cb|
|
69
|
-
cb.call(worker)
|
70
|
-
end
|
28
|
+
def initialize(worker_count)
|
29
|
+
@worker_count = worker_count
|
30
|
+
@queue_server = Server.new
|
31
|
+
@worker_pool = []
|
32
|
+
@url = DRb.start_service("drbunix:", @queue_server).uri
|
71
33
|
end
|
72
34
|
|
73
35
|
def start
|
74
|
-
@
|
75
|
-
|
76
|
-
DRb.stop_service
|
77
|
-
|
78
|
-
begin
|
79
|
-
after_fork(worker)
|
80
|
-
rescue => setup_exception; end
|
81
|
-
|
82
|
-
queue = DRbObject.new_with_uri(@url)
|
83
|
-
|
84
|
-
while job = queue.pop
|
85
|
-
klass = job[0]
|
86
|
-
method = job[1]
|
87
|
-
reporter = job[2]
|
88
|
-
result = klass.with_info_handler reporter do
|
89
|
-
Minitest.run_one_method(klass, method)
|
90
|
-
end
|
91
|
-
|
92
|
-
add_setup_exception(result, setup_exception) if setup_exception
|
93
|
-
|
94
|
-
begin
|
95
|
-
queue.record(reporter, result)
|
96
|
-
rescue DRb::DRbConnError
|
97
|
-
result.failures.map! do |failure|
|
98
|
-
if failure.respond_to?(:error)
|
99
|
-
# minitest >5.14.0
|
100
|
-
error = DRb::DRbRemoteError.new(failure.error)
|
101
|
-
else
|
102
|
-
error = DRb::DRbRemoteError.new(failure.exception)
|
103
|
-
end
|
104
|
-
Minitest::UnexpectedError.new(error)
|
105
|
-
end
|
106
|
-
queue.record(reporter, result)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
ensure
|
110
|
-
run_cleanup(worker)
|
111
|
-
end
|
36
|
+
@worker_pool = @worker_count.times.map do |worker|
|
37
|
+
Worker.new(worker, @url).start
|
112
38
|
end
|
113
39
|
end
|
114
40
|
|
115
41
|
def <<(work)
|
116
|
-
@
|
42
|
+
@queue_server << work
|
117
43
|
end
|
118
44
|
|
119
|
-
def
|
120
|
-
@
|
121
|
-
@pool.each { |pid| Process.waitpid pid }
|
122
|
-
|
123
|
-
if @queue.length > 0
|
124
|
-
raise "Queue not empty, but all workers have finished. This probably means that a worker crashed and #{@queue.length} tests were missed."
|
125
|
-
end
|
45
|
+
def size
|
46
|
+
@worker_count
|
126
47
|
end
|
127
48
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
49
|
+
def shutdown
|
50
|
+
@queue_server.shutdown
|
51
|
+
@worker_pool.each { |pid| Process.waitpid pid }
|
52
|
+
end
|
132
53
|
end
|
133
54
|
end
|
134
55
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
module Testing
|
5
|
+
class ParallelizeExecutor # :nodoc:
|
6
|
+
attr_reader :size, :parallelize_with, :threshold
|
7
|
+
|
8
|
+
def initialize(size:, with:, threshold: ActiveSupport.test_parallelization_threshold)
|
9
|
+
@size = size
|
10
|
+
@parallelize_with = with
|
11
|
+
@threshold = threshold
|
12
|
+
@parallelized = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
parallelize if should_parallelize?
|
17
|
+
show_execution_info
|
18
|
+
|
19
|
+
parallel_executor.start if parallelized?
|
20
|
+
end
|
21
|
+
|
22
|
+
def <<(work)
|
23
|
+
parallel_executor << work if parallelized?
|
24
|
+
end
|
25
|
+
|
26
|
+
def shutdown
|
27
|
+
parallel_executor.shutdown if parallelized?
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def parallel_executor
|
32
|
+
@parallel_executor ||= build_parallel_executor
|
33
|
+
end
|
34
|
+
|
35
|
+
def build_parallel_executor
|
36
|
+
case parallelize_with
|
37
|
+
when :processes
|
38
|
+
Testing::Parallelization.new(size)
|
39
|
+
when :threads
|
40
|
+
ActiveSupport::TestCase.lock_threads = false if defined?(ActiveSupport::TestCase.lock_threads)
|
41
|
+
Minitest::Parallel::Executor.new(size)
|
42
|
+
else
|
43
|
+
raise ArgumentError, "#{parallelize_with} is not a supported parallelization executor."
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def parallelize
|
48
|
+
@parallelized = true
|
49
|
+
Minitest::Test.parallelize_me!
|
50
|
+
end
|
51
|
+
|
52
|
+
def parallelized?
|
53
|
+
@parallelized
|
54
|
+
end
|
55
|
+
|
56
|
+
def should_parallelize?
|
57
|
+
(ENV["PARALLEL_WORKERS"] || tests_count > threshold) && many_workers?
|
58
|
+
end
|
59
|
+
|
60
|
+
def many_workers?
|
61
|
+
size > 1
|
62
|
+
end
|
63
|
+
|
64
|
+
def tests_count
|
65
|
+
@tests_count ||= Minitest::Runnable.runnables.sum { |runnable| runnable.runnable_methods.size }
|
66
|
+
end
|
67
|
+
|
68
|
+
def show_execution_info
|
69
|
+
puts execution_info
|
70
|
+
end
|
71
|
+
|
72
|
+
def execution_info
|
73
|
+
if parallelized?
|
74
|
+
"Running #{tests_count} tests in parallel using #{parallel_executor.size} #{parallelize_with}"
|
75
|
+
elsif many_workers?
|
76
|
+
"Running #{tests_count} tests in a single process (parallelization threshold is #{threshold})"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module ActiveSupport
|
4
4
|
module Testing
|
5
|
-
module Stream
|
5
|
+
module Stream # :nodoc:
|
6
6
|
private
|
7
7
|
def silence_stream(stream)
|
8
8
|
old_stream = stream.dup
|
@@ -14,18 +14,16 @@ module ActiveSupport
|
|
14
14
|
old_stream.close
|
15
15
|
end
|
16
16
|
|
17
|
-
def quietly
|
17
|
+
def quietly(&block)
|
18
18
|
silence_stream(STDOUT) do
|
19
|
-
silence_stream(STDERR)
|
20
|
-
yield
|
21
|
-
end
|
19
|
+
silence_stream(STDERR, &block)
|
22
20
|
end
|
23
21
|
end
|
24
22
|
|
25
23
|
def capture(stream)
|
26
24
|
stream = stream.to_s
|
27
25
|
captured_stream = Tempfile.new(stream)
|
28
|
-
stream_io = eval("$#{stream}")
|
26
|
+
stream_io = eval("$#{stream}", binding, __FILE__, __LINE__)
|
29
27
|
origin_stream = stream_io.dup
|
30
28
|
stream_io.reopen(captured_stream)
|
31
29
|
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$VERBOSE = true
|
4
|
+
Warning[:deprecated] = true
|
5
|
+
|
6
|
+
module ActiveSupport
|
7
|
+
module RaiseWarnings # :nodoc:
|
8
|
+
PROJECT_ROOT = File.expand_path("../../../../", __dir__)
|
9
|
+
ALLOWED_WARNINGS = Regexp.union(
|
10
|
+
/circular require considered harmful.*delayed_job/, # Bug in delayed job.
|
11
|
+
|
12
|
+
# Expected non-verbose warning emitted by Rails.
|
13
|
+
/Ignoring .*\.yml because it has expired/,
|
14
|
+
/Failed to validate the schema cache because/,
|
15
|
+
)
|
16
|
+
|
17
|
+
SUPPRESSED_WARNINGS = Regexp.union(
|
18
|
+
# TODO: remove if https://github.com/mikel/mail/pull/1557 or similar fix
|
19
|
+
%r{/lib/mail/parsers/.*statement not reached},
|
20
|
+
%r{/lib/mail/parsers/.*assigned but unused variable - disp_type_s},
|
21
|
+
%r{/lib/mail/parsers/.*assigned but unused variable - testEof}
|
22
|
+
)
|
23
|
+
|
24
|
+
def warn(message, *)
|
25
|
+
return if SUPPRESSED_WARNINGS.match?(message)
|
26
|
+
|
27
|
+
super
|
28
|
+
|
29
|
+
return unless message.include?(PROJECT_ROOT)
|
30
|
+
return if ALLOWED_WARNINGS.match?(message)
|
31
|
+
return unless ENV["RAILS_STRICT_WARNINGS"] || ENV["CI"]
|
32
|
+
|
33
|
+
raise message
|
34
|
+
end
|
35
|
+
ruby2_keywords :warn if respond_to?(:ruby2_keywords, true)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
Warning.singleton_class.prepend(ActiveSupport::RaiseWarnings)
|
@@ -4,7 +4,7 @@ module ActiveSupport
|
|
4
4
|
module Testing
|
5
5
|
# Logs a "PostsControllerTest: test name" heading before each test to
|
6
6
|
# make test.log easier to search and follow along with.
|
7
|
-
module TaggedLogging
|
7
|
+
module TaggedLogging # :nodoc:
|
8
8
|
attr_writer :tagged_logger
|
9
9
|
|
10
10
|
def before_setup
|