activesupport 6.0.3.4 → 6.1.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +371 -448
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/active_support.rb +13 -1
- data/lib/active_support/array_inquirer.rb +4 -2
- data/lib/active_support/backtrace_cleaner.rb +3 -3
- data/lib/active_support/benchmarkable.rb +1 -1
- data/lib/active_support/cache.rb +85 -44
- data/lib/active_support/cache/file_store.rb +4 -3
- data/lib/active_support/cache/mem_cache_store.rb +29 -18
- data/lib/active_support/cache/memory_store.rb +46 -26
- data/lib/active_support/cache/redis_cache_store.rb +27 -27
- data/lib/active_support/cache/strategy/local_cache.rb +21 -6
- data/lib/active_support/callbacks.rb +65 -56
- data/lib/active_support/concern.rb +46 -2
- data/lib/active_support/configurable.rb +3 -3
- data/lib/active_support/configuration_file.rb +46 -0
- data/lib/active_support/core_ext.rb +1 -1
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/class/attribute.rb +34 -44
- data/lib/active_support/core_ext/class/subclasses.rb +17 -38
- data/lib/active_support/core_ext/date/conversions.rb +2 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +13 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/enumerable.rb +76 -4
- data/lib/active_support/core_ext/hash/conversions.rb +2 -2
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
- data/lib/active_support/core_ext/hash/except.rb +1 -1
- data/lib/active_support/core_ext/hash/keys.rb +1 -1
- data/lib/active_support/core_ext/hash/slice.rb +3 -2
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/marshal.rb +2 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +23 -29
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -4
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +38 -28
- data/lib/active_support/core_ext/module/introspection.rb +1 -25
- data/lib/active_support/core_ext/name_error.rb +29 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +22 -18
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/json.rb +13 -2
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/range/compare_range.rb +9 -3
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
- data/lib/active_support/core_ext/regexp.rb +8 -1
- data/lib/active_support/core_ext/string/access.rb +5 -24
- data/lib/active_support/core_ext/string/conversions.rb +1 -0
- data/lib/active_support/core_ext/string/inflections.rb +38 -4
- data/lib/active_support/core_ext/string/inquiry.rb +1 -0
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/string/output_safety.rb +10 -10
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
- data/lib/active_support/core_ext/time/calculations.rb +27 -3
- data/lib/active_support/core_ext/time/conversions.rb +2 -0
- data/lib/active_support/core_ext/uri.rb +5 -1
- data/lib/active_support/current_attributes.rb +7 -2
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/dependencies.rb +43 -19
- data/lib/active_support/deprecation.rb +6 -1
- data/lib/active_support/deprecation/behaviors.rb +15 -2
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +0 -1
- data/lib/active_support/deprecation/method_wrappers.rb +3 -2
- data/lib/active_support/deprecation/proxy_wrappers.rb +3 -3
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/descendants_tracker.rb +6 -2
- data/lib/active_support/duration.rb +71 -22
- data/lib/active_support/duration/iso8601_serializer.rb +15 -9
- data/lib/active_support/encrypted_file.rb +19 -2
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/evented_file_update_checker.rb +69 -133
- data/lib/active_support/fork_tracker.rb +62 -0
- data/lib/active_support/gem_version.rb +2 -2
- data/lib/active_support/hash_with_indifferent_access.rb +43 -24
- data/lib/active_support/i18n_railtie.rb +14 -19
- data/lib/active_support/inflector/inflections.rb +1 -2
- data/lib/active_support/inflector/methods.rb +35 -31
- data/lib/active_support/inflector/transliterate.rb +4 -4
- data/lib/active_support/json/decoding.rb +4 -4
- data/lib/active_support/json/encoding.rb +5 -1
- data/lib/active_support/key_generator.rb +1 -1
- data/lib/active_support/locale/en.yml +7 -3
- data/lib/active_support/log_subscriber.rb +8 -0
- data/lib/active_support/logger.rb +1 -1
- data/lib/active_support/logger_silence.rb +2 -26
- data/lib/active_support/logger_thread_safe_level.rb +34 -12
- data/lib/active_support/message_encryptor.rb +4 -7
- data/lib/active_support/message_verifier.rb +5 -5
- data/lib/active_support/messages/metadata.rb +9 -1
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +6 -5
- data/lib/active_support/multibyte/chars.rb +4 -42
- data/lib/active_support/multibyte/unicode.rb +9 -83
- data/lib/active_support/notifications.rb +32 -5
- data/lib/active_support/notifications/fanout.rb +23 -8
- data/lib/active_support/notifications/instrumenter.rb +6 -15
- data/lib/active_support/number_helper.rb +29 -14
- data/lib/active_support/number_helper/number_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_currency_converter.rb +3 -7
- 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 +1 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +3 -3
- data/lib/active_support/number_helper/rounding_helper.rb +12 -28
- data/lib/active_support/option_merger.rb +3 -2
- data/lib/active_support/ordered_options.rb +8 -2
- data/lib/active_support/parameter_filter.rb +16 -11
- data/lib/active_support/per_thread_registry.rb +1 -1
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +23 -1
- data/lib/active_support/rescuable.rb +4 -4
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +4 -2
- data/lib/active_support/subscriber.rb +12 -7
- data/lib/active_support/tagged_logging.rb +29 -4
- data/lib/active_support/testing/assertions.rb +18 -11
- data/lib/active_support/testing/parallelization.rb +12 -95
- data/lib/active_support/testing/parallelization/server.rb +78 -0
- data/lib/active_support/testing/parallelization/worker.rb +100 -0
- data/lib/active_support/testing/time_helpers.rb +40 -3
- data/lib/active_support/time_with_zone.rb +67 -43
- data/lib/active_support/values/time_zone.rb +20 -10
- data/lib/active_support/xml_mini/rexml.rb +8 -1
- metadata +34 -36
- 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/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/rails.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# This is private interface.
|
3
|
+
# This is a private interface.
|
4
4
|
#
|
5
5
|
# Rails components cherry pick from Active Support as needed, but there are a
|
6
6
|
# few features that are used for sure in some way or another and it is not worth
|
@@ -13,9 +13,6 @@
|
|
13
13
|
# Defines Object#blank? and Object#present?.
|
14
14
|
require "active_support/core_ext/object/blank"
|
15
15
|
|
16
|
-
# Rails own autoload, eager_load, etc.
|
17
|
-
require "active_support/dependencies/autoload"
|
18
|
-
|
19
16
|
# Support for ClassMethods and the included macro.
|
20
17
|
require "active_support/concern"
|
21
18
|
|
@@ -22,12 +22,25 @@ module ActiveSupport
|
|
22
22
|
app.reloader.before_class_unload { ActiveSupport::CurrentAttributes.clear_all }
|
23
23
|
app.executor.to_run { ActiveSupport::CurrentAttributes.reset_all }
|
24
24
|
app.executor.to_complete { ActiveSupport::CurrentAttributes.reset_all }
|
25
|
+
|
26
|
+
ActiveSupport.on_load(:active_support_test_case) do
|
27
|
+
require "active_support/current_attributes/test_helper"
|
28
|
+
include ActiveSupport::CurrentAttributes::TestHelper
|
29
|
+
end
|
25
30
|
end
|
26
31
|
|
27
32
|
initializer "active_support.deprecation_behavior" do |app|
|
28
33
|
if deprecation = app.config.active_support.deprecation
|
29
34
|
ActiveSupport::Deprecation.behavior = deprecation
|
30
35
|
end
|
36
|
+
|
37
|
+
if disallowed_deprecation = app.config.active_support.disallowed_deprecation
|
38
|
+
ActiveSupport::Deprecation.disallowed_behavior = disallowed_deprecation
|
39
|
+
end
|
40
|
+
|
41
|
+
if disallowed_warnings = app.config.active_support.disallowed_deprecation_warnings
|
42
|
+
ActiveSupport::Deprecation.disallowed_warnings = disallowed_warnings
|
43
|
+
end
|
31
44
|
end
|
32
45
|
|
33
46
|
# Sets the default value for Time.zone
|
@@ -65,15 +78,24 @@ module ActiveSupport
|
|
65
78
|
initializer "active_support.set_configs" do |app|
|
66
79
|
app.config.active_support.each do |k, v|
|
67
80
|
k = "#{k}="
|
68
|
-
ActiveSupport.
|
81
|
+
ActiveSupport.public_send(k, v) if ActiveSupport.respond_to? k
|
69
82
|
end
|
70
83
|
end
|
71
84
|
|
72
85
|
initializer "active_support.set_hash_digest_class" do |app|
|
73
86
|
config.after_initialize do
|
74
87
|
if app.config.active_support.use_sha1_digests
|
88
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
89
|
+
config.active_support.use_sha1_digests is deprecated and will
|
90
|
+
be removed from Rails 6.2. Use
|
91
|
+
config.active_support.hash_digest_class = ::Digest::SHA1 instead.
|
92
|
+
MSG
|
75
93
|
ActiveSupport::Digest.hash_digest_class = ::Digest::SHA1
|
76
94
|
end
|
95
|
+
|
96
|
+
if klass = app.config.active_support.hash_digest_class
|
97
|
+
ActiveSupport::Digest.hash_digest_class = klass
|
98
|
+
end
|
77
99
|
end
|
78
100
|
end
|
79
101
|
end
|
@@ -14,12 +14,12 @@ module ActiveSupport
|
|
14
14
|
end
|
15
15
|
|
16
16
|
module ClassMethods
|
17
|
-
#
|
17
|
+
# Registers exception classes with a handler to be called by <tt>rescue_with_handler</tt>.
|
18
18
|
#
|
19
19
|
# <tt>rescue_from</tt> receives a series of exception classes or class
|
20
|
-
# names, and a trailing <tt>:with</tt>
|
21
|
-
#
|
22
|
-
# be given.
|
20
|
+
# names, and an exception handler specified by a trailing <tt>:with</tt>
|
21
|
+
# option containing the name of a method or a Proc object. Alternatively, a block
|
22
|
+
# can be given as the handler.
|
23
23
|
#
|
24
24
|
# Handlers that take one argument will be called with the exception, so
|
25
25
|
# that the exception can be inspected when dealing with it.
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/security_utils"
|
4
|
+
require "active_support/messages/rotator"
|
5
|
+
|
6
|
+
module ActiveSupport
|
7
|
+
# The ActiveSupport::SecureCompareRotator is a wrapper around +ActiveSupport::SecurityUtils.secure_compare+
|
8
|
+
# and allows you to rotate a previously defined value to a new one.
|
9
|
+
#
|
10
|
+
# It can be used as follow:
|
11
|
+
#
|
12
|
+
# rotator = ActiveSupport::SecureCompareRotator.new('new_production_value')
|
13
|
+
# rotator.rotate('previous_production_value')
|
14
|
+
# rotator.secure_compare!('previous_production_value')
|
15
|
+
#
|
16
|
+
# One real use case example would be to rotate a basic auth credentials:
|
17
|
+
#
|
18
|
+
# class MyController < ApplicationController
|
19
|
+
# def authenticate_request
|
20
|
+
# rotator = ActiveSupport::SecureComparerotator.new('new_password')
|
21
|
+
# rotator.rotate('old_password')
|
22
|
+
#
|
23
|
+
# authenticate_or_request_with_http_basic do |username, password|
|
24
|
+
# rotator.secure_compare!(password)
|
25
|
+
# rescue ActiveSupport::SecureCompareRotator::InvalidMatch
|
26
|
+
# false
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
class SecureCompareRotator
|
31
|
+
include SecurityUtils
|
32
|
+
prepend Messages::Rotator
|
33
|
+
|
34
|
+
InvalidMatch = Class.new(StandardError)
|
35
|
+
|
36
|
+
def initialize(value, **_options)
|
37
|
+
@value = value
|
38
|
+
end
|
39
|
+
|
40
|
+
def secure_compare!(other_value, on_rotation: @on_rotation)
|
41
|
+
secure_compare(@value, other_value) ||
|
42
|
+
run_rotations(on_rotation) { |wrapper| wrapper.secure_compare!(other_value) } ||
|
43
|
+
raise(InvalidMatch)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
def build_rotation(previous_value, _options)
|
48
|
+
self.class.new(previous_value)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -1,30 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "digest/sha2"
|
4
|
-
|
5
3
|
module ActiveSupport
|
6
4
|
module SecurityUtils
|
7
5
|
# Constant time string comparison, for fixed length strings.
|
8
6
|
#
|
9
7
|
# The values compared should be of fixed length, such as strings
|
10
8
|
# that have already been processed by HMAC. Raises in case of length mismatch.
|
11
|
-
def fixed_length_secure_compare(a, b)
|
12
|
-
raise ArgumentError, "string length mismatch." unless a.bytesize == b.bytesize
|
13
9
|
|
14
|
-
|
10
|
+
if defined?(OpenSSL.fixed_length_secure_compare)
|
11
|
+
def fixed_length_secure_compare(a, b)
|
12
|
+
OpenSSL.fixed_length_secure_compare(a, b)
|
13
|
+
end
|
14
|
+
else
|
15
|
+
def fixed_length_secure_compare(a, b)
|
16
|
+
raise ArgumentError, "string length mismatch." unless a.bytesize == b.bytesize
|
17
|
+
|
18
|
+
l = a.unpack "C#{a.bytesize}"
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
20
|
+
res = 0
|
21
|
+
b.each_byte { |byte| res |= byte ^ l.shift }
|
22
|
+
res == 0
|
23
|
+
end
|
19
24
|
end
|
20
25
|
module_function :fixed_length_secure_compare
|
21
26
|
|
22
|
-
#
|
27
|
+
# Secure string comparison for strings of variable length.
|
23
28
|
#
|
24
|
-
#
|
25
|
-
# via
|
29
|
+
# While a timing attack would not be able to discern the content of
|
30
|
+
# a secret compared via secure_compare, it is possible to determine
|
31
|
+
# the secret length. This should be considered when using secure_compare
|
32
|
+
# to compare weak, short secrets to user input.
|
26
33
|
def secure_compare(a, b)
|
27
|
-
|
34
|
+
a.length == b.length && fixed_length_secure_compare(a, b)
|
28
35
|
end
|
29
36
|
module_function :secure_compare
|
30
37
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/symbol/starts_ends_with"
|
4
|
+
|
3
5
|
module ActiveSupport
|
4
6
|
# Wrapping a string in this class gives you a prettier way to test
|
5
7
|
# for equality. The value returned by <tt>Rails.env</tt> is wrapped
|
@@ -19,11 +21,11 @@ module ActiveSupport
|
|
19
21
|
class StringInquirer < String
|
20
22
|
private
|
21
23
|
def respond_to_missing?(method_name, include_private = false)
|
22
|
-
(
|
24
|
+
method_name.end_with?("?") || super
|
23
25
|
end
|
24
26
|
|
25
27
|
def method_missing(method_name, *arguments)
|
26
|
-
if method_name
|
28
|
+
if method_name.end_with?("?")
|
27
29
|
self == method_name[0..-2]
|
28
30
|
else
|
29
31
|
super
|
@@ -31,15 +31,16 @@ module ActiveSupport
|
|
31
31
|
class Subscriber
|
32
32
|
class << self
|
33
33
|
# Attach the subscriber to a namespace.
|
34
|
-
def attach_to(namespace, subscriber = new, notifier = ActiveSupport::Notifications)
|
34
|
+
def attach_to(namespace, subscriber = new, notifier = ActiveSupport::Notifications, inherit_all: false)
|
35
35
|
@namespace = namespace
|
36
36
|
@subscriber = subscriber
|
37
37
|
@notifier = notifier
|
38
|
+
@inherit_all = inherit_all
|
38
39
|
|
39
40
|
subscribers << subscriber
|
40
41
|
|
41
42
|
# Add event subscribers for all existing methods on the class.
|
42
|
-
subscriber
|
43
|
+
fetch_public_methods(subscriber, inherit_all).each do |event|
|
43
44
|
add_event_subscriber(event)
|
44
45
|
end
|
45
46
|
end
|
@@ -55,7 +56,7 @@ module ActiveSupport
|
|
55
56
|
subscribers.delete(subscriber)
|
56
57
|
|
57
58
|
# Remove event subscribers of all existing methods on the class.
|
58
|
-
subscriber
|
59
|
+
fetch_public_methods(subscriber, true).each do |event|
|
59
60
|
remove_event_subscriber(event)
|
60
61
|
end
|
61
62
|
|
@@ -81,18 +82,18 @@ module ActiveSupport
|
|
81
82
|
attr_reader :subscriber, :notifier, :namespace
|
82
83
|
|
83
84
|
def add_event_subscriber(event) # :doc:
|
84
|
-
return if invalid_event?(event
|
85
|
+
return if invalid_event?(event)
|
85
86
|
|
86
87
|
pattern = prepare_pattern(event)
|
87
88
|
|
88
|
-
# Don't add multiple subscribers (
|
89
|
+
# Don't add multiple subscribers (e.g. if methods are redefined).
|
89
90
|
return if pattern_subscribed?(pattern)
|
90
91
|
|
91
92
|
subscriber.patterns[pattern] = notifier.subscribe(pattern, subscriber)
|
92
93
|
end
|
93
94
|
|
94
95
|
def remove_event_subscriber(event) # :doc:
|
95
|
-
return if invalid_event?(event
|
96
|
+
return if invalid_event?(event)
|
96
97
|
|
97
98
|
pattern = prepare_pattern(event)
|
98
99
|
|
@@ -107,7 +108,7 @@ module ActiveSupport
|
|
107
108
|
end
|
108
109
|
|
109
110
|
def invalid_event?(event)
|
110
|
-
%
|
111
|
+
%i{ start finish }.include?(event.to_sym)
|
111
112
|
end
|
112
113
|
|
113
114
|
def prepare_pattern(event)
|
@@ -117,6 +118,10 @@ module ActiveSupport
|
|
117
118
|
def pattern_subscribed?(pattern)
|
118
119
|
subscriber.patterns.key?(pattern)
|
119
120
|
end
|
121
|
+
|
122
|
+
def fetch_public_methods(subscriber, inherit_all)
|
123
|
+
subscriber.public_methods(inherit_all) - Subscriber.public_instance_methods(true)
|
124
|
+
end
|
120
125
|
end
|
121
126
|
|
122
127
|
attr_reader :patterns # :nodoc:
|
@@ -8,11 +8,20 @@ require "active_support/logger"
|
|
8
8
|
module ActiveSupport
|
9
9
|
# Wraps any standard Logger object to provide tagging capabilities.
|
10
10
|
#
|
11
|
+
# May be called with a block:
|
12
|
+
#
|
11
13
|
# logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
|
12
14
|
# logger.tagged('BCX') { logger.info 'Stuff' } # Logs "[BCX] Stuff"
|
13
15
|
# logger.tagged('BCX', "Jason") { logger.info 'Stuff' } # Logs "[BCX] [Jason] Stuff"
|
14
16
|
# logger.tagged('BCX') { logger.tagged('Jason') { logger.info 'Stuff' } } # Logs "[BCX] [Jason] Stuff"
|
15
17
|
#
|
18
|
+
# If called without a block, a new logger will be returned with applied tags:
|
19
|
+
#
|
20
|
+
# logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
|
21
|
+
# logger.tagged("BCX").info "Stuff" # Logs "[BCX] Stuff"
|
22
|
+
# logger.tagged("BCX", "Jason").info "Stuff" # Logs "[BCX] [Jason] Stuff"
|
23
|
+
# logger.tagged("BCX").tagged("Jason").info "Stuff" # Logs "[BCX] [Jason] Stuff"
|
24
|
+
#
|
16
25
|
# This is used by the default Rails.logger as configured by Railties to make
|
17
26
|
# it easy to stamp log lines with subdomains, request ids, and anything else
|
18
27
|
# to aid debugging of multi-user production applications.
|
@@ -31,9 +40,10 @@ module ActiveSupport
|
|
31
40
|
end
|
32
41
|
|
33
42
|
def push_tags(*tags)
|
34
|
-
tags.flatten
|
35
|
-
|
36
|
-
|
43
|
+
tags.flatten!
|
44
|
+
tags.reject!(&:blank?)
|
45
|
+
current_tags.concat tags
|
46
|
+
tags
|
37
47
|
end
|
38
48
|
|
39
49
|
def pop_tags(size = 1)
|
@@ -60,6 +70,14 @@ module ActiveSupport
|
|
60
70
|
end
|
61
71
|
end
|
62
72
|
|
73
|
+
module LocalTagStorage # :nodoc:
|
74
|
+
attr_accessor :current_tags
|
75
|
+
|
76
|
+
def self.extended(base)
|
77
|
+
base.current_tags = []
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
63
81
|
def self.new(logger)
|
64
82
|
logger = logger.dup
|
65
83
|
|
@@ -77,7 +95,14 @@ module ActiveSupport
|
|
77
95
|
delegate :push_tags, :pop_tags, :clear_tags!, to: :formatter
|
78
96
|
|
79
97
|
def tagged(*tags)
|
80
|
-
|
98
|
+
if block_given?
|
99
|
+
formatter.tagged(*tags) { yield self }
|
100
|
+
else
|
101
|
+
logger = ActiveSupport::TaggedLogging.new(self)
|
102
|
+
logger.formatter.extend LocalTagStorage
|
103
|
+
logger.push_tags(*formatter.current_tags, *tags)
|
104
|
+
logger
|
105
|
+
end
|
81
106
|
end
|
82
107
|
|
83
108
|
def flush
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/enumerable"
|
4
|
+
|
3
5
|
module ActiveSupport
|
4
6
|
module Testing
|
5
7
|
module Assertions
|
@@ -30,6 +32,8 @@ module ActiveSupport
|
|
30
32
|
# end
|
31
33
|
def assert_nothing_raised
|
32
34
|
yield
|
35
|
+
rescue => error
|
36
|
+
raise Minitest::UnexpectedError.new(error)
|
33
37
|
end
|
34
38
|
|
35
39
|
# Test numeric difference between the return value of an expression as a
|
@@ -87,7 +91,7 @@ module ActiveSupport
|
|
87
91
|
else
|
88
92
|
difference = args[0] || 1
|
89
93
|
message = args[1]
|
90
|
-
|
94
|
+
Array(expression).index_with(difference)
|
91
95
|
end
|
92
96
|
|
93
97
|
exps = expressions.keys.map { |e|
|
@@ -95,7 +99,7 @@ module ActiveSupport
|
|
95
99
|
}
|
96
100
|
before = exps.map(&:call)
|
97
101
|
|
98
|
-
retval =
|
102
|
+
retval = assert_nothing_raised(&block)
|
99
103
|
|
100
104
|
expressions.zip(exps, before) do |(code, diff), exp, before_value|
|
101
105
|
error = "#{code.inspect} didn't change by #{diff}"
|
@@ -172,10 +176,10 @@ module ActiveSupport
|
|
172
176
|
exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
|
173
177
|
|
174
178
|
before = exp.call
|
175
|
-
retval =
|
179
|
+
retval = assert_nothing_raised(&block)
|
176
180
|
|
177
181
|
unless from == UNTRACKED
|
178
|
-
error = "
|
182
|
+
error = "Expected change from #{from.inspect}"
|
179
183
|
error = "#{message}.\n#{error}" if message
|
180
184
|
assert from === before, error
|
181
185
|
end
|
@@ -185,12 +189,10 @@ module ActiveSupport
|
|
185
189
|
error = "#{expression.inspect} didn't change"
|
186
190
|
error = "#{error}. It was already #{to}" if before == to
|
187
191
|
error = "#{message}.\n#{error}" if message
|
188
|
-
|
192
|
+
assert_not_equal before, after, error
|
189
193
|
|
190
194
|
unless to == UNTRACKED
|
191
|
-
error = "
|
192
|
-
error = "#{error}Expected: #{to.inspect}\n"
|
193
|
-
error = "#{error} Actual: #{after.inspect}"
|
195
|
+
error = "Expected change to #{to}\n"
|
194
196
|
error = "#{message}.\n#{error}" if message
|
195
197
|
assert to === after, error
|
196
198
|
end
|
@@ -214,12 +216,17 @@ module ActiveSupport
|
|
214
216
|
exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
|
215
217
|
|
216
218
|
before = exp.call
|
217
|
-
retval =
|
219
|
+
retval = assert_nothing_raised(&block)
|
218
220
|
after = exp.call
|
219
221
|
|
220
|
-
error = "#{expression.inspect}
|
222
|
+
error = "#{expression.inspect} changed"
|
221
223
|
error = "#{message}.\n#{error}" if message
|
222
|
-
|
224
|
+
|
225
|
+
if before.nil?
|
226
|
+
assert_nil after, error
|
227
|
+
else
|
228
|
+
assert_equal before, after, error
|
229
|
+
end
|
223
230
|
|
224
231
|
retval
|
225
232
|
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,27 @@ 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
45
|
def shutdown
|
120
|
-
@
|
121
|
-
@
|
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
|
46
|
+
@queue_server.shutdown
|
47
|
+
@worker_pool.each { |pid| Process.waitpid pid }
|
126
48
|
end
|
127
|
-
|
128
|
-
private
|
129
|
-
def add_setup_exception(result, setup_exception)
|
130
|
-
result.failures.prepend Minitest::UnexpectedError.new(setup_exception)
|
131
|
-
end
|
132
49
|
end
|
133
50
|
end
|
134
51
|
end
|