activesupport 6.0.4.4 → 7.0.4.1
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.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +257 -532
- data/MIT-LICENSE +1 -1
- data/lib/active_support/actionable_error.rb +1 -1
- data/lib/active_support/array_inquirer.rb +2 -2
- data/lib/active_support/backtrace_cleaner.rb +5 -5
- data/lib/active_support/benchmarkable.rb +3 -3
- data/lib/active_support/cache/file_store.rb +16 -10
- data/lib/active_support/cache/mem_cache_store.rb +163 -42
- data/lib/active_support/cache/memory_store.rb +57 -29
- data/lib/active_support/cache/null_store.rb +10 -2
- data/lib/active_support/cache/redis_cache_store.rb +79 -98
- data/lib/active_support/cache/strategy/local_cache.rb +49 -57
- data/lib/active_support/cache.rb +378 -179
- data/lib/active_support/callbacks.rb +230 -122
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +49 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +9 -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 +13 -12
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- 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/array.rb +1 -0
- 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 +9 -22
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +9 -9
- data/lib/active_support/core_ext/date/conversions.rb +16 -15
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date.rb +1 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +17 -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/conversions.rb +13 -13
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +1 -0
- data/lib/active_support/core_ext/digest/uuid.rb +39 -13
- data/lib/active_support/core_ext/enumerable.rb +164 -23
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +2 -3
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +2 -2
- data/lib/active_support/core_ext/hash/slice.rb +3 -2
- 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 +25 -29
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +26 -13
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +40 -36
- data/lib/active_support/core_ext/module/introspection.rb +1 -25
- data/lib/active_support/core_ext/name_error.rb +23 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +80 -73
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric.rb +1 -0
- 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 +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +11 -0
- data/lib/active_support/core_ext/object/json.rb +42 -26
- data/lib/active_support/core_ext/object/to_query.rb +2 -2
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/object/with_options.rb +20 -1
- data/lib/active_support/core_ext/pathname/existence.rb +21 -0
- data/lib/active_support/core_ext/pathname.rb +3 -0
- data/lib/active_support/core_ext/range/compare_range.rb +6 -25
- data/lib/active_support/core_ext/range/conversions.rb +8 -8
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -20
- data/lib/active_support/core_ext/range/overlaps.rb +1 -1
- data/lib/active_support/core_ext/range.rb +1 -1
- data/lib/active_support/core_ext/regexp.rb +8 -1
- data/lib/active_support/core_ext/securerandom.rb +1 -1
- 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 +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +39 -5
- 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 +92 -41
- 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/time/calculations.rb +25 -7
- data/lib/active_support/core_ext/time/conversions.rb +15 -12
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +7 -22
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/core_ext/uri.rb +3 -23
- 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 +39 -16
- 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 +23 -7
- 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 +6 -5
- data/lib/active_support/deprecation/proxy_wrappers.rb +4 -4
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/deprecation.rb +7 -2
- data/lib/active_support/descendants_tracker.rb +174 -64
- 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 -10
- data/lib/active_support/duration.rb +134 -55
- data/lib/active_support/encrypted_configuration.rb +13 -2
- data/lib/active_support/encrypted_file.rb +32 -3
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/evented_file_update_checker.rb +72 -138
- 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 +43 -21
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/fork_tracker.rb +71 -0
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/hash_with_indifferent_access.rb +51 -25
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/i18n_railtie.rb +14 -19
- data/lib/active_support/inflector/inflections.rb +24 -9
- data/lib/active_support/inflector/methods.rb +29 -49
- data/lib/active_support/inflector/transliterate.rb +5 -5
- data/lib/active_support/isolated_execution_state.rb +72 -0
- data/lib/active_support/json/decoding.rb +4 -4
- data/lib/active_support/json/encoding.rb +8 -4
- data/lib/active_support/key_generator.rb +23 -6
- data/lib/active_support/lazy_load_hooks.rb +28 -4
- data/lib/active_support/locale/en.yml +8 -4
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +23 -5
- 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 -21
- data/lib/active_support/message_encryptor.rb +16 -13
- data/lib/active_support/message_verifier.rb +50 -18
- data/lib/active_support/messages/metadata.rb +2 -2
- 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 +13 -52
- data/lib/active_support/multibyte/unicode.rb +1 -87
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +110 -69
- data/lib/active_support/notifications/instrumenter.rb +37 -29
- data/lib/active_support/notifications.rb +55 -28
- data/lib/active_support/number_helper/number_converter.rb +2 -4
- 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 +2 -2
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -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 +29 -16
- data/lib/active_support/option_merger.rb +11 -18
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +9 -3
- data/lib/active_support/parameter_filter.rb +21 -11
- data/lib/active_support/per_thread_registry.rb +6 -1
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +77 -5
- data/lib/active_support/reloader.rb +1 -1
- data/lib/active_support/rescuable.rb +16 -16
- data/lib/active_support/ruby_features.rb +7 -0
- 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 +2 -2
- data/lib/active_support/subscriber.rb +19 -25
- data/lib/active_support/tagged_logging.rb +31 -6
- data/lib/active_support/test_case.rb +13 -21
- data/lib/active_support/testing/assertions.rb +50 -13
- data/lib/active_support/testing/deprecation.rb +52 -1
- data/lib/active_support/testing/isolation.rb +2 -2
- data/lib/active_support/testing/method_call_assertions.rb +5 -5
- 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 +76 -0
- data/lib/active_support/testing/stream.rb +3 -5
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +53 -5
- data/lib/active_support/time_with_zone.rb +126 -62
- data/lib/active_support/values/time_zone.rb +54 -23
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +1 -1
- 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 +4 -4
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
- data/lib/active_support/xml_mini/rexml.rb +9 -2
- data/lib/active_support/xml_mini.rb +5 -4
- data/lib/active_support.rb +29 -1
- metadata +46 -45
- 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/dependencies/zeitwerk_integration.rb +0 -117
@@ -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)
|
@@ -47,7 +57,7 @@ module ActiveSupport
|
|
47
57
|
def current_tags
|
48
58
|
# We use our object ID here to avoid conflicting with other instances
|
49
59
|
thread_key = @thread_key ||= "activesupport_tagged_logging_tags:#{object_id}"
|
50
|
-
|
60
|
+
IsolatedExecutionState[thread_key] ||= []
|
51
61
|
end
|
52
62
|
|
53
63
|
def tags_text
|
@@ -60,8 +70,16 @@ 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
|
-
logger = logger.
|
82
|
+
logger = logger.clone
|
65
83
|
|
66
84
|
if logger.formatter
|
67
85
|
logger.formatter = logger.formatter.dup
|
@@ -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
|
@@ -12,6 +12,7 @@ require "active_support/testing/constant_lookup"
|
|
12
12
|
require "active_support/testing/time_helpers"
|
13
13
|
require "active_support/testing/file_fixtures"
|
14
14
|
require "active_support/testing/parallelization"
|
15
|
+
require "active_support/testing/parallelize_executor"
|
15
16
|
require "concurrent/utility/processor_counter"
|
16
17
|
|
17
18
|
module ActiveSupport
|
@@ -71,26 +72,17 @@ module ActiveSupport
|
|
71
72
|
#
|
72
73
|
# The threaded parallelization uses minitest's parallel executor directly.
|
73
74
|
# The processes parallelization uses a Ruby DRb server.
|
74
|
-
|
75
|
+
#
|
76
|
+
# Because parallelization presents an overhead, it is only enabled when the
|
77
|
+
# number of tests to run is above the +threshold+ param. The default value is
|
78
|
+
# 50, and it's configurable via +config.active_support.test_parallelization_threshold+.
|
79
|
+
def parallelize(workers: :number_of_processors, with: :processes, threshold: ActiveSupport.test_parallelization_threshold)
|
75
80
|
workers = Concurrent.physical_processor_count if workers == :number_of_processors
|
76
81
|
workers = ENV["PARALLEL_WORKERS"].to_i if ENV["PARALLEL_WORKERS"]
|
77
82
|
|
78
83
|
return if workers <= 1
|
79
84
|
|
80
|
-
|
81
|
-
when :processes
|
82
|
-
Testing::Parallelization.new(workers)
|
83
|
-
when :threads
|
84
|
-
Minitest::Parallel::Executor.new(workers)
|
85
|
-
else
|
86
|
-
raise ArgumentError, "#{with} is not a supported parallelization executor."
|
87
|
-
end
|
88
|
-
|
89
|
-
self.lock_threads = false if defined?(self.lock_threads) && with == :threads
|
90
|
-
|
91
|
-
Minitest.parallel_executor = executor
|
92
|
-
|
93
|
-
parallelize_me!
|
85
|
+
Minitest.parallel_executor = ActiveSupport::Testing::ParallelizeExecutor.new(size: workers, with: with, threshold: threshold)
|
94
86
|
end
|
95
87
|
|
96
88
|
# Set up hook for parallel testing. This can be used if you have multiple
|
@@ -107,9 +99,7 @@ module ActiveSupport
|
|
107
99
|
# end
|
108
100
|
# end
|
109
101
|
def parallelize_setup(&block)
|
110
|
-
ActiveSupport::Testing::Parallelization.after_fork_hook
|
111
|
-
yield worker
|
112
|
-
end
|
102
|
+
ActiveSupport::Testing::Parallelization.after_fork_hook(&block)
|
113
103
|
end
|
114
104
|
|
115
105
|
# Clean up hook for parallel testing. This can be used to drop databases
|
@@ -126,9 +116,7 @@ module ActiveSupport
|
|
126
116
|
# end
|
127
117
|
# end
|
128
118
|
def parallelize_teardown(&block)
|
129
|
-
ActiveSupport::Testing::Parallelization.run_cleanup_hook
|
130
|
-
yield worker
|
131
|
-
end
|
119
|
+
ActiveSupport::Testing::Parallelization.run_cleanup_hook(&block)
|
132
120
|
end
|
133
121
|
end
|
134
122
|
|
@@ -159,5 +147,9 @@ module ActiveSupport
|
|
159
147
|
alias :assert_not_same :refute_same
|
160
148
|
|
161
149
|
ActiveSupport.run_load_hooks(:active_support_test_case, self)
|
150
|
+
|
151
|
+
def inspect # :nodoc:
|
152
|
+
Object.instance_method(:to_s).bind_call(self)
|
153
|
+
end
|
162
154
|
end
|
163
155
|
end
|
@@ -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_or_warn("assert_difference", &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}"
|
@@ -155,7 +159,7 @@ module ActiveSupport
|
|
155
159
|
# @object = 42
|
156
160
|
# end
|
157
161
|
#
|
158
|
-
# The keyword arguments
|
162
|
+
# The keyword arguments +:from+ and +:to+ can be given to specify the
|
159
163
|
# expected initial value and the expected value after the block was
|
160
164
|
# executed.
|
161
165
|
#
|
@@ -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_or_warn("assert_changes", &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
|
+
refute_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
|
@@ -205,24 +207,59 @@ module ActiveSupport
|
|
205
207
|
# post :create, params: { status: { ok: true } }
|
206
208
|
# end
|
207
209
|
#
|
210
|
+
# Provide the optional keyword argument :from to specify the expected
|
211
|
+
# initial value.
|
212
|
+
#
|
213
|
+
# assert_no_changes -> { Status.all_good? }, from: true do
|
214
|
+
# post :create, params: { status: { ok: true } }
|
215
|
+
# end
|
216
|
+
#
|
208
217
|
# An error message can be specified.
|
209
218
|
#
|
210
219
|
# assert_no_changes -> { Status.all_good? }, 'Expected the status to be good' do
|
211
220
|
# post :create, params: { status: { ok: false } }
|
212
221
|
# end
|
213
|
-
def assert_no_changes(expression, message = nil, &block)
|
222
|
+
def assert_no_changes(expression, message = nil, from: UNTRACKED, &block)
|
214
223
|
exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
|
215
224
|
|
216
225
|
before = exp.call
|
217
|
-
retval =
|
226
|
+
retval = _assert_nothing_raised_or_warn("assert_no_changes", &block)
|
227
|
+
|
228
|
+
unless from == UNTRACKED
|
229
|
+
error = "Expected initial value of #{from.inspect}"
|
230
|
+
error = "#{message}.\n#{error}" if message
|
231
|
+
assert from === before, error
|
232
|
+
end
|
233
|
+
|
218
234
|
after = exp.call
|
219
235
|
|
220
|
-
error = "#{expression.inspect}
|
236
|
+
error = "#{expression.inspect} changed"
|
221
237
|
error = "#{message}.\n#{error}" if message
|
222
|
-
|
238
|
+
|
239
|
+
if before.nil?
|
240
|
+
assert_nil after, error
|
241
|
+
else
|
242
|
+
assert_equal before, after, error
|
243
|
+
end
|
223
244
|
|
224
245
|
retval
|
225
246
|
end
|
247
|
+
|
248
|
+
private
|
249
|
+
def _assert_nothing_raised_or_warn(assertion, &block)
|
250
|
+
assert_nothing_raised(&block)
|
251
|
+
rescue Minitest::UnexpectedError => e
|
252
|
+
if tagged_logger && tagged_logger.warn?
|
253
|
+
warning = <<~MSG
|
254
|
+
#{self.class} - #{name}: #{e.error.class} raised.
|
255
|
+
If you expected this exception, use `assert_raises` as near to the code that raises as possible.
|
256
|
+
Other block based assertions (e.g. `#{assertion}`) can be used, as long as `assert_raises` is inside their block.
|
257
|
+
MSG
|
258
|
+
tagged_logger.warn warning
|
259
|
+
end
|
260
|
+
|
261
|
+
raise
|
262
|
+
end
|
226
263
|
end
|
227
264
|
end
|
228
265
|
end
|
@@ -4,7 +4,30 @@ require "active_support/deprecation"
|
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
6
|
module Testing
|
7
|
-
module Deprecation
|
7
|
+
module Deprecation
|
8
|
+
# Asserts that a matching deprecation warning was emitted by the given deprecator during the execution of the yielded block.
|
9
|
+
#
|
10
|
+
# assert_deprecated(/foo/, CustomDeprecator) do
|
11
|
+
# CustomDeprecator.warn "foo should no longer be used"
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# The +match+ object may be a +Regexp+, or +String+ appearing in the message.
|
15
|
+
#
|
16
|
+
# assert_deprecated('foo', CustomDeprecator) do
|
17
|
+
# CustomDeprecator.warn "foo should no longer be used"
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# If the +match+ is omitted (or explicitly +nil+), any deprecation warning will match.
|
21
|
+
#
|
22
|
+
# assert_deprecated(nil, CustomDeprecator) do
|
23
|
+
# CustomDeprecator.warn "foo should no longer be used"
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# If no +deprecator+ is given, defaults to ActiveSupport::Deprecation.
|
27
|
+
#
|
28
|
+
# assert_deprecated do
|
29
|
+
# ActiveSupport::Deprecation.warn "foo should no longer be used"
|
30
|
+
# end
|
8
31
|
def assert_deprecated(match = nil, deprecator = nil, &block)
|
9
32
|
result, warnings = collect_deprecations(deprecator, &block)
|
10
33
|
assert !warnings.empty?, "Expected a deprecation warning within the block but received none"
|
@@ -15,12 +38,40 @@ module ActiveSupport
|
|
15
38
|
result
|
16
39
|
end
|
17
40
|
|
41
|
+
# Asserts that no deprecation warnings are emitted by the given deprecator during the execution of the yielded block.
|
42
|
+
#
|
43
|
+
# assert_not_deprecated(CustomDeprecator) do
|
44
|
+
# CustomDeprecator.warn "message" # fails assertion
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# If no +deprecator+ is given, defaults to ActiveSupport::Deprecation.
|
48
|
+
#
|
49
|
+
# assert_not_deprecated do
|
50
|
+
# ActiveSupport::Deprecation.warn "message" # fails assertion
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# assert_not_deprecated do
|
54
|
+
# CustomDeprecator.warn "message" # passes assertion
|
55
|
+
# end
|
18
56
|
def assert_not_deprecated(deprecator = nil, &block)
|
19
57
|
result, deprecations = collect_deprecations(deprecator, &block)
|
20
58
|
assert deprecations.empty?, "Expected no deprecation warning within the block but received #{deprecations.size}: \n #{deprecations * "\n "}"
|
21
59
|
result
|
22
60
|
end
|
23
61
|
|
62
|
+
# Returns an array of all the deprecation warnings emitted by the given
|
63
|
+
# +deprecator+ during the execution of the yielded block.
|
64
|
+
#
|
65
|
+
# collect_deprecations(CustomDeprecator) do
|
66
|
+
# CustomDeprecator.warn "message"
|
67
|
+
# end # => ["message"]
|
68
|
+
#
|
69
|
+
# If no +deprecator+ is given, defaults to ActiveSupport::Deprecation.
|
70
|
+
#
|
71
|
+
# collect_deprecations do
|
72
|
+
# CustomDeprecator.warn "custom message"
|
73
|
+
# ActiveSupport::Deprecation.warn "message"
|
74
|
+
# end # => ["message"]
|
24
75
|
def collect_deprecations(deprecator = nil)
|
25
76
|
deprecator ||= ActiveSupport::Deprecation
|
26
77
|
old_behavior = deprecator.behavior
|
@@ -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
|
@@ -63,7 +63,7 @@ module ActiveSupport
|
|
63
63
|
module Subprocess
|
64
64
|
ORIG_ARGV = ARGV.dup unless defined?(ORIG_ARGV)
|
65
65
|
|
66
|
-
#
|
66
|
+
# Complicated H4X to get this working in windows / jruby with
|
67
67
|
# no forking.
|
68
68
|
def run_in_isolation(&blk)
|
69
69
|
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,16 +17,16 @@ 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: nil)
|
20
|
+
def assert_called_with(object, method_name, args, returns: nil, &block)
|
21
21
|
mock = Minitest::Mock.new
|
22
22
|
|
23
|
-
if args.all?
|
23
|
+
if args.all?(Array)
|
24
24
|
args.each { |arg| mock.expect(:call, returns, arg) }
|
25
25
|
else
|
26
26
|
mock.expect(:call, returns, args)
|
27
27
|
end
|
28
28
|
|
29
|
-
object.stub(method_name, mock)
|
29
|
+
object.stub(method_name, mock, &block)
|
30
30
|
|
31
31
|
mock.verify
|
32
32
|
end
|
@@ -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
|