activesupport 5.2.4.3 → 7.0.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 +244 -459
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -3
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/array_inquirer.rb +2 -2
- data/lib/active_support/backtrace_cleaner.rb +31 -5
- data/lib/active_support/benchmarkable.rb +3 -3
- data/lib/active_support/cache/file_store.rb +47 -41
- data/lib/active_support/cache/mem_cache_store.rb +151 -40
- data/lib/active_support/cache/memory_store.rb +68 -34
- data/lib/active_support/cache/null_store.rb +16 -3
- data/lib/active_support/cache/redis_cache_store.rb +103 -101
- data/lib/active_support/cache/strategy/local_cache.rb +56 -64
- data/lib/active_support/cache.rb +333 -116
- data/lib/active_support/callbacks.rb +244 -128
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +72 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +16 -0
- data/lib/active_support/concurrency/share_lock.rb +2 -3
- data/lib/active_support/configurable.rb +15 -16
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +15 -7
- data/lib/active_support/core_ext/array/conversions.rb +18 -17
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- data/lib/active_support/core_ext/array/extract.rb +21 -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 +2 -1
- 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 +32 -47
- 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 +15 -14
- 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 +41 -51
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +13 -14
- 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 +241 -76
- 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_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +2 -2
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +2 -31
- data/lib/active_support/core_ext/hash/slice.rb +6 -27
- data/lib/active_support/core_ext/hash.rb +1 -2
- data/lib/active_support/core_ext/integer/multiple.rb +1 -1
- 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/kernel.rb +0 -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 +32 -39
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +35 -28
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +70 -33
- data/lib/active_support/core_ext/module/introspection.rb +16 -15
- data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
- data/lib/active_support/core_ext/module.rb +0 -1
- data/lib/active_support/core_ext/name_error.rb +23 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +132 -129
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric.rb +1 -1
- data/lib/active_support/core_ext/object/acts_like.rb +29 -5
- data/lib/active_support/core_ext/object/blank.rb +3 -4
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +14 -110
- data/lib/active_support/core_ext/object/json.rb +44 -27
- data/lib/active_support/core_ext/object/to_query.rb +2 -2
- data/lib/active_support/core_ext/object/try.rb +24 -14
- data/lib/active_support/core_ext/object/with_options.rb +21 -2
- 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 +23 -27
- data/lib/active_support/core_ext/range/conversions.rb +32 -30
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +1 -2
- 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 -5
- data/lib/active_support/core_ext/securerandom.rb +23 -3
- data/lib/active_support/core_ext/string/access.rb +5 -16
- data/lib/active_support/core_ext/string/conversions.rb +3 -2
- data/lib/active_support/core_ext/string/filters.rb +42 -1
- data/lib/active_support/core_ext/string/inflections.rb +46 -7
- data/lib/active_support/core_ext/string/inquiry.rb +2 -1
- data/lib/active_support/core_ext/string/multibyte.rb +6 -5
- data/lib/active_support/core_ext/string/output_safety.rb +129 -20
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/string/strip.rb +3 -1
- 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 +59 -10
- 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 -22
- 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 +47 -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 +60 -715
- data/lib/active_support/deprecation/behaviors.rb +21 -5
- 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 +18 -23
- data/lib/active_support/deprecation/proxy_wrappers.rb +31 -8
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/deprecation.rb +7 -2
- data/lib/active_support/descendants_tracker.rb +190 -34
- data/lib/active_support/digest.rb +5 -3
- data/lib/active_support/duration/iso8601_parser.rb +5 -7
- data/lib/active_support/duration/iso8601_serializer.rb +27 -15
- data/lib/active_support/duration.rb +149 -67
- data/lib/active_support/encrypted_configuration.rb +12 -5
- data/lib/active_support/encrypted_file.rb +23 -5
- 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 +85 -122
- 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 +44 -21
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/file_update_checker.rb +0 -1
- data/lib/active_support/fork_tracker.rb +71 -0
- data/lib/active_support/gem_version.rb +5 -5
- data/lib/active_support/hash_with_indifferent_access.rb +73 -43
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +2 -0
- data/lib/active_support/i18n_railtie.rb +15 -8
- data/lib/active_support/inflector/inflections.rb +25 -14
- data/lib/active_support/inflector/methods.rb +38 -71
- data/lib/active_support/inflector/transliterate.rb +47 -18
- data/lib/active_support/isolated_execution_state.rb +72 -0
- data/lib/active_support/json/decoding.rb +25 -26
- data/lib/active_support/json/encoding.rb +14 -6
- data/lib/active_support/key_generator.rb +23 -38
- data/lib/active_support/lazy_load_hooks.rb +19 -5
- data/lib/active_support/locale/en.rb +33 -0
- 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 +51 -11
- data/lib/active_support/logger.rb +6 -22
- data/lib/active_support/logger_silence.rb +11 -19
- data/lib/active_support/logger_thread_safe_level.rb +45 -10
- data/lib/active_support/message_encryptor.rb +20 -19
- data/lib/active_support/message_verifier.rb +53 -21
- data/lib/active_support/messages/metadata.rb +13 -4
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +10 -9
- data/lib/active_support/multibyte/chars.rb +17 -76
- data/lib/active_support/multibyte/unicode.rb +7 -331
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +163 -37
- data/lib/active_support/notifications/instrumenter.rb +90 -11
- data/lib/active_support/notifications.rb +88 -30
- data/lib/active_support/number_helper/number_converter.rb +6 -9
- data/lib/active_support/number_helper/number_to_currency_converter.rb +12 -12
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +4 -3
- data/lib/active_support/number_helper/number_to_human_converter.rb +4 -3
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +5 -4
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +3 -2
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +12 -7
- data/lib/active_support/number_helper/rounding_helper.rb +12 -32
- data/lib/active_support/number_helper.rb +36 -12
- data/lib/active_support/option_merger.rb +15 -4
- data/lib/active_support/ordered_hash.rb +2 -2
- data/lib/active_support/ordered_options.rb +14 -4
- data/lib/active_support/parameter_filter.rb +138 -0
- data/lib/active_support/per_thread_registry.rb +6 -1
- data/lib/active_support/rails.rb +1 -10
- data/lib/active_support/railtie.rb +77 -5
- data/lib/active_support/reloader.rb +5 -6
- data/lib/active_support/rescuable.rb +8 -8
- 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 -3
- data/lib/active_support/subscriber.rb +79 -46
- data/lib/active_support/tagged_logging.rb +58 -9
- data/lib/active_support/test_case.rb +79 -0
- data/lib/active_support/testing/assertions.rb +62 -11
- data/lib/active_support/testing/deprecation.rb +52 -2
- data/lib/active_support/testing/file_fixtures.rb +2 -0
- data/lib/active_support/testing/isolation.rb +4 -4
- data/lib/active_support/testing/method_call_assertions.rb +32 -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 +55 -0
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/stream.rb +4 -7
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +60 -14
- data/lib/active_support/time_with_zone.rb +139 -64
- data/lib/active_support/values/time_zone.rb +66 -30
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +3 -4
- data/lib/active_support/xml_mini/libxml.rb +7 -7
- data/lib/active_support/xml_mini/libxmlsax.rb +5 -5
- data/lib/active_support/xml_mini/nokogiri.rb +6 -6
- data/lib/active_support/xml_mini/nokogirisax.rb +4 -4
- data/lib/active_support/xml_mini/rexml.rb +11 -4
- data/lib/active_support/xml_mini.rb +7 -14
- data/lib/active_support.rb +30 -1
- metadata +64 -35
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -9
- data/lib/active_support/core_ext/hash/compact.rb +0 -29
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -32
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
- data/lib/active_support/core_ext/marshal.rb +0 -24
- data/lib/active_support/core_ext/module/reachable.rb +0 -11
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -28
- data/lib/active_support/core_ext/range/include_range.rb +0 -3
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -11,6 +11,9 @@ require "active_support/testing/isolation"
|
|
11
11
|
require "active_support/testing/constant_lookup"
|
12
12
|
require "active_support/testing/time_helpers"
|
13
13
|
require "active_support/testing/file_fixtures"
|
14
|
+
require "active_support/testing/parallelization"
|
15
|
+
require "active_support/testing/parallelize_executor"
|
16
|
+
require "concurrent/utility/processor_counter"
|
14
17
|
|
15
18
|
module ActiveSupport
|
16
19
|
class TestCase < ::Minitest::Test
|
@@ -39,6 +42,82 @@ module ActiveSupport
|
|
39
42
|
def test_order
|
40
43
|
ActiveSupport.test_order ||= :random
|
41
44
|
end
|
45
|
+
|
46
|
+
# Parallelizes the test suite.
|
47
|
+
#
|
48
|
+
# Takes a +workers+ argument that controls how many times the process
|
49
|
+
# is forked. For each process a new database will be created suffixed
|
50
|
+
# with the worker number.
|
51
|
+
#
|
52
|
+
# test-database-0
|
53
|
+
# test-database-1
|
54
|
+
#
|
55
|
+
# If <tt>ENV["PARALLEL_WORKERS"]</tt> is set the workers argument will be ignored
|
56
|
+
# and the environment variable will be used instead. This is useful for CI
|
57
|
+
# environments, or other environments where you may need more workers than
|
58
|
+
# you do for local testing.
|
59
|
+
#
|
60
|
+
# If the number of workers is set to +1+ or fewer, the tests will not be
|
61
|
+
# parallelized.
|
62
|
+
#
|
63
|
+
# If +workers+ is set to +:number_of_processors+, the number of workers will be
|
64
|
+
# set to the actual core count on the machine you are on.
|
65
|
+
#
|
66
|
+
# The default parallelization method is to fork processes. If you'd like to
|
67
|
+
# use threads instead you can pass <tt>with: :threads</tt> to the +parallelize+
|
68
|
+
# method. Note the threaded parallelization does not create multiple
|
69
|
+
# database and will not work with system tests at this time.
|
70
|
+
#
|
71
|
+
# parallelize(workers: :number_of_processors, with: :threads)
|
72
|
+
#
|
73
|
+
# The threaded parallelization uses minitest's parallel executor directly.
|
74
|
+
# The processes parallelization uses a Ruby DRb server.
|
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)
|
80
|
+
workers = Concurrent.physical_processor_count if workers == :number_of_processors
|
81
|
+
workers = ENV["PARALLEL_WORKERS"].to_i if ENV["PARALLEL_WORKERS"]
|
82
|
+
|
83
|
+
return if workers <= 1
|
84
|
+
|
85
|
+
Minitest.parallel_executor = ActiveSupport::Testing::ParallelizeExecutor.new(size: workers, with: with, threshold: threshold)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Set up hook for parallel testing. This can be used if you have multiple
|
89
|
+
# databases or any behavior that needs to be run after the process is forked
|
90
|
+
# but before the tests run.
|
91
|
+
#
|
92
|
+
# Note: this feature is not available with the threaded parallelization.
|
93
|
+
#
|
94
|
+
# In your +test_helper.rb+ add the following:
|
95
|
+
#
|
96
|
+
# class ActiveSupport::TestCase
|
97
|
+
# parallelize_setup do
|
98
|
+
# # create databases
|
99
|
+
# end
|
100
|
+
# end
|
101
|
+
def parallelize_setup(&block)
|
102
|
+
ActiveSupport::Testing::Parallelization.after_fork_hook(&block)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Clean up hook for parallel testing. This can be used to drop databases
|
106
|
+
# if your app uses multiple write/read databases or other clean up before
|
107
|
+
# the tests finish. This runs before the forked process is closed.
|
108
|
+
#
|
109
|
+
# Note: this feature is not available with the threaded parallelization.
|
110
|
+
#
|
111
|
+
# In your +test_helper.rb+ add the following:
|
112
|
+
#
|
113
|
+
# class ActiveSupport::TestCase
|
114
|
+
# parallelize_teardown do
|
115
|
+
# # drop databases
|
116
|
+
# end
|
117
|
+
# end
|
118
|
+
def parallelize_teardown(&block)
|
119
|
+
ActiveSupport::Testing::Parallelization.run_cleanup_hook(&block)
|
120
|
+
end
|
42
121
|
end
|
43
122
|
|
44
123
|
alias_method :method_name, :name
|
@@ -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}"
|
@@ -113,11 +117,23 @@ module ActiveSupport
|
|
113
117
|
# post :create, params: { article: invalid_attributes }
|
114
118
|
# end
|
115
119
|
#
|
120
|
+
# A lambda can be passed in and evaluated.
|
121
|
+
#
|
122
|
+
# assert_no_difference -> { Article.count } do
|
123
|
+
# post :create, params: { article: invalid_attributes }
|
124
|
+
# end
|
125
|
+
#
|
116
126
|
# An error message can be specified.
|
117
127
|
#
|
118
128
|
# assert_no_difference 'Article.count', 'An Article should not be created' do
|
119
129
|
# post :create, params: { article: invalid_attributes }
|
120
130
|
# end
|
131
|
+
#
|
132
|
+
# An array of expressions can also be passed in and evaluated.
|
133
|
+
#
|
134
|
+
# assert_no_difference [ 'Article.count', -> { Post.count } ] do
|
135
|
+
# post :create, params: { article: invalid_attributes }
|
136
|
+
# end
|
121
137
|
def assert_no_difference(expression, message = nil, &block)
|
122
138
|
assert_difference expression, 0, message, &block
|
123
139
|
end
|
@@ -143,7 +159,7 @@ module ActiveSupport
|
|
143
159
|
# @object = 42
|
144
160
|
# end
|
145
161
|
#
|
146
|
-
# The keyword arguments
|
162
|
+
# The keyword arguments +:from+ and +:to+ can be given to specify the
|
147
163
|
# expected initial value and the expected value after the block was
|
148
164
|
# executed.
|
149
165
|
#
|
@@ -160,10 +176,10 @@ module ActiveSupport
|
|
160
176
|
exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
|
161
177
|
|
162
178
|
before = exp.call
|
163
|
-
retval =
|
179
|
+
retval = _assert_nothing_raised_or_warn("assert_changes", &block)
|
164
180
|
|
165
181
|
unless from == UNTRACKED
|
166
|
-
error = "
|
182
|
+
error = "Expected change from #{from.inspect}"
|
167
183
|
error = "#{message}.\n#{error}" if message
|
168
184
|
assert from === before, error
|
169
185
|
end
|
@@ -173,10 +189,10 @@ module ActiveSupport
|
|
173
189
|
error = "#{expression.inspect} didn't change"
|
174
190
|
error = "#{error}. It was already #{to}" if before == to
|
175
191
|
error = "#{message}.\n#{error}" if message
|
176
|
-
|
192
|
+
refute_equal before, after, error
|
177
193
|
|
178
194
|
unless to == UNTRACKED
|
179
|
-
error = "
|
195
|
+
error = "Expected change to #{to}\n"
|
180
196
|
error = "#{message}.\n#{error}" if message
|
181
197
|
assert to === after, error
|
182
198
|
end
|
@@ -191,24 +207,59 @@ module ActiveSupport
|
|
191
207
|
# post :create, params: { status: { ok: true } }
|
192
208
|
# end
|
193
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
|
+
#
|
194
217
|
# An error message can be specified.
|
195
218
|
#
|
196
219
|
# assert_no_changes -> { Status.all_good? }, 'Expected the status to be good' do
|
197
220
|
# post :create, params: { status: { ok: false } }
|
198
221
|
# end
|
199
|
-
def assert_no_changes(expression, message = nil, &block)
|
222
|
+
def assert_no_changes(expression, message = nil, from: UNTRACKED, &block)
|
200
223
|
exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
|
201
224
|
|
202
225
|
before = exp.call
|
203
|
-
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
|
+
|
204
234
|
after = exp.call
|
205
235
|
|
206
|
-
error = "#{expression.inspect}
|
236
|
+
error = "#{expression.inspect} changed"
|
207
237
|
error = "#{message}.\n#{error}" if message
|
208
|
-
|
238
|
+
|
239
|
+
if before.nil?
|
240
|
+
assert_nil after, error
|
241
|
+
else
|
242
|
+
assert_equal before, after, error
|
243
|
+
end
|
209
244
|
|
210
245
|
retval
|
211
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
|
212
263
|
end
|
213
264
|
end
|
214
265
|
end
|
@@ -1,11 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/deprecation"
|
4
|
-
require "active_support/core_ext/regexp"
|
5
4
|
|
6
5
|
module ActiveSupport
|
7
6
|
module Testing
|
8
|
-
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
|
9
31
|
def assert_deprecated(match = nil, deprecator = nil, &block)
|
10
32
|
result, warnings = collect_deprecations(deprecator, &block)
|
11
33
|
assert !warnings.empty?, "Expected a deprecation warning within the block but received none"
|
@@ -16,12 +38,40 @@ module ActiveSupport
|
|
16
38
|
result
|
17
39
|
end
|
18
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
|
19
56
|
def assert_not_deprecated(deprecator = nil, &block)
|
20
57
|
result, deprecations = collect_deprecations(deprecator, &block)
|
21
58
|
assert deprecations.empty?, "Expected no deprecation warning within the block but received #{deprecations.size}: \n #{deprecations * "\n "}"
|
22
59
|
result
|
23
60
|
end
|
24
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"]
|
25
75
|
def collect_deprecations(deprecator = nil)
|
26
76
|
deprecator ||= ActiveSupport::Deprecation
|
27
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
|
@@ -56,14 +56,14 @@ module ActiveSupport
|
|
56
56
|
write.close
|
57
57
|
result = read.read
|
58
58
|
Process.wait2(pid)
|
59
|
-
result.
|
59
|
+
result.unpack1("m")
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
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"
|
@@ -98,7 +98,7 @@ module ActiveSupport
|
|
98
98
|
nil
|
99
99
|
end
|
100
100
|
|
101
|
-
return tmpfile.read.
|
101
|
+
return tmpfile.read.unpack1("m")
|
102
102
|
end
|
103
103
|
end
|
104
104
|
end
|
@@ -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
|
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
|
@@ -35,6 +35,33 @@ module ActiveSupport
|
|
35
35
|
assert_called(object, method_name, message, times: 0, &block)
|
36
36
|
end
|
37
37
|
|
38
|
+
def assert_called_on_instance_of(klass, method_name, message = nil, times: 1, returns: nil)
|
39
|
+
times_called = 0
|
40
|
+
klass.define_method("stubbed_#{method_name}") do |*|
|
41
|
+
times_called += 1
|
42
|
+
|
43
|
+
returns
|
44
|
+
end
|
45
|
+
|
46
|
+
klass.alias_method "original_#{method_name}", method_name
|
47
|
+
klass.alias_method method_name, "stubbed_#{method_name}"
|
48
|
+
|
49
|
+
yield
|
50
|
+
|
51
|
+
error = "Expected #{method_name} to be called #{times} times, but was called #{times_called} times"
|
52
|
+
error = "#{message}.\n#{error}" if message
|
53
|
+
|
54
|
+
assert_equal times, times_called, error
|
55
|
+
ensure
|
56
|
+
klass.alias_method method_name, "original_#{method_name}"
|
57
|
+
klass.undef_method "original_#{method_name}"
|
58
|
+
klass.undef_method "stubbed_#{method_name}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def assert_not_called_on_instance_of(klass, method_name, message = nil, &block)
|
62
|
+
assert_called_on_instance_of(klass, method_name, message, times: 0, &block)
|
63
|
+
end
|
64
|
+
|
38
65
|
def stub_any_instance(klass, instance: klass.new)
|
39
66
|
klass.stub(:new, instance) { yield instance }
|
40
67
|
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
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "drb"
|
4
|
+
require "drb/unix" unless Gem.win_platform?
|
5
|
+
require "active_support/core_ext/module/attribute_accessors"
|
6
|
+
require "active_support/testing/parallelization/server"
|
7
|
+
require "active_support/testing/parallelization/worker"
|
8
|
+
|
9
|
+
module ActiveSupport
|
10
|
+
module Testing
|
11
|
+
class Parallelization # :nodoc:
|
12
|
+
@@after_fork_hooks = []
|
13
|
+
|
14
|
+
def self.after_fork_hook(&blk)
|
15
|
+
@@after_fork_hooks << blk
|
16
|
+
end
|
17
|
+
|
18
|
+
cattr_reader :after_fork_hooks
|
19
|
+
|
20
|
+
@@run_cleanup_hooks = []
|
21
|
+
|
22
|
+
def self.run_cleanup_hook(&blk)
|
23
|
+
@@run_cleanup_hooks << blk
|
24
|
+
end
|
25
|
+
|
26
|
+
cattr_reader :run_cleanup_hooks
|
27
|
+
|
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
|
33
|
+
end
|
34
|
+
|
35
|
+
def start
|
36
|
+
@worker_pool = @worker_count.times.map do |worker|
|
37
|
+
Worker.new(worker, @url).start
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def <<(work)
|
42
|
+
@queue_server << work
|
43
|
+
end
|
44
|
+
|
45
|
+
def size
|
46
|
+
@worker_count
|
47
|
+
end
|
48
|
+
|
49
|
+
def shutdown
|
50
|
+
@queue_server.shutdown
|
51
|
+
@worker_pool.each { |pid| Process.waitpid pid }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|