1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Merge pull request #31803 from rmosolgo/rm-dependencies

Fix infinite loop when unloading autoloaded modules
This commit is contained in:
Rafael França 2018-01-26 13:45:08 -05:00 committed by GitHub
commit 2f9549d4f4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 0 deletions

View file

@ -447,6 +447,7 @@ module ActiveSupport #:nodoc:
mod = Module.new
into.const_set const_name, mod
autoloaded_constants << qualified_name unless autoload_once_paths.include?(base_path)
autoloaded_constants.uniq!
mod
end

View file

@ -185,6 +185,61 @@ class DependenciesTest < ActiveSupport::TestCase
end
end
# Regression see https://github.com/rails/rails/issues/31694
def test_included_constant_that_changes_to_have_exception_then_back_does_not_loop_forever
# This constant references a nested constant whose namespace will be auto-generated
parent_constant = <<-RUBY
class ConstantReloadError
AnotherConstant::ReloadError
end
RUBY
# This constant's namespace will be auto-generated,
# also, we'll edit it to contain an error at load-time
child_constant = <<-RUBY
class AnotherConstant::ReloadError
# no_such_method_as_this
end
RUBY
# Create a version which contains an error during loading
child_constant_with_error = child_constant.sub("# no_such_method_as_this", "no_such_method_as_this")
fixtures_path = File.join(__dir__, "autoloading_fixtures")
Dir.mktmpdir(nil, fixtures_path) do |tmpdir|
# Set up the file structure where constants will be loaded from
child_constant_path = "#{tmpdir}/another_constant/reload_error.rb"
File.write("#{tmpdir}/constant_reload_error.rb", parent_constant)
Dir.mkdir("#{tmpdir}/another_constant")
File.write(child_constant_path, child_constant_with_error)
tmpdir_name = tmpdir.split("/").last
with_loading("autoloading_fixtures/#{tmpdir_name}") do
# Load the file, with the error:
assert_raises(NameError) {
ConstantReloadError
}
Timeout.timeout(0.1) do
# Remove the constant, as if Rails development middleware is reloading changed files:
ActiveSupport::Dependencies.remove_unloadable_constants!
refute defined?(AnotherConstant::ReloadError)
end
# Change the file, so that it is **correct** this time:
File.write(child_constant_path, child_constant)
# Again: Remove the constant, as if Rails development middleware is reloading changed files:
ActiveSupport::Dependencies.remove_unloadable_constants!
refute defined?(AnotherConstant::ReloadError)
# Now, reload the _fixed_ constant:
assert ConstantReloadError
assert AnotherConstant::ReloadError
end
end
end
def test_module_loading
with_autoloading_fixtures do
assert_kind_of Module, A