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

358 lines
10 KiB
Ruby
Raw Normal View History

2019-02-11 15:44:25 -05:00
# frozen_string_literal: true
require "set"
2019-02-11 15:44:25 -05:00
require "isolation/abstract_unit"
class ZeitwerkIntegrationTest < ActiveSupport::TestCase
include ActiveSupport::Testing::Isolation
def setup
build_app
end
def boot(env = "development")
app(env)
end
def teardown
teardown_app
end
def deps
ActiveSupport::Dependencies
end
test "The integration is minimally looking good" do
2019-02-11 15:44:25 -05:00
boot
assert Rails.autoloaders.zeitwerk_enabled?
assert_instance_of Zeitwerk::Loader, Rails.autoloaders.main
assert_instance_of Zeitwerk::Loader, Rails.autoloaders.once
assert_equal [Rails.autoloaders.main, Rails.autoloaders.once], Rails.autoloaders.to_a
2019-02-11 15:44:25 -05:00
end
test "autoloaders inflect with Active Support" do
app_file "config/initializers/inflections.rb", <<-RUBY
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.acronym 'RESTful'
end
RUBY
app_file "app/controllers/restful_controller.rb", <<-RUBY
class RESTfulController < ApplicationController
end
RUBY
boot
basename = "restful_controller"
abspath = "#{Rails.root}/app/controllers/#{basename}.rb"
camelized = "RESTfulController"
Rails.autoloaders.each do |autoloader|
assert_equal camelized, autoloader.inflector.camelize(basename, abspath)
end
assert RESTfulController
end
2021-08-16 23:23:51 -04:00
test "the once autoloader can autoload from initializers" do
app_file "extras0/x.rb", "X = 0"
app_file "extras1/y.rb", "Y = 0"
# We should be able to configure autoload_once_paths in
# config/application.rb and in config/environments/*.rb.
add_to_config 'config.autoload_once_paths << "#{Rails.root}/extras0"'
add_to_env_config "development", 'config.autoload_once_paths << "#{Rails.root}/extras1"'
# Collections should br frozen after bootstrap, and you are ready to
# autoload with the once autoloader. In particular, from initializers.
$config_autoload_once_paths_is_frozen = false
$global_autoload_once_paths_is_frozen = false
add_to_config <<~RUBY
initializer :test_autoload_once_paths_is_frozen, after: :bootstrap_hook do
$config_autoload_once_paths_is_frozen = config.autoload_once_paths.frozen?
$global_autoload_once_paths_is_frozen = ActiveSupport::Dependencies.autoload_once_paths.frozen?
X
end
RUBY
app_file "config/initializers/autoload_Y.rb", "Y"
# Preconditions.
assert_not Object.const_defined?(:X)
assert_not Object.const_defined?(:Y)
boot
assert Object.const_defined?(:X)
assert Object.const_defined?(:Y)
assert $config_autoload_once_paths_is_frozen
assert $global_autoload_once_paths_is_frozen
end
test "the once autoloader can eager load" do
app_file "app/serializers/money_serializer.rb", "MoneySerializer = :dummy_value"
add_to_config 'config.autoload_once_paths << "#{Rails.root}/app/serializers"'
add_to_config 'config.eager_load_paths << "#{Rails.root}/app/serializers"'
assert_not Object.const_defined?(:MoneySerializer)
boot("production")
assert Object.const_defined?(:MoneySerializer)
end
2019-02-11 15:44:25 -05:00
test "eager loading loads the application code" do
$zeitwerk_integration_test_user = false
$zeitwerk_integration_test_post = false
app_file "app/models/user.rb", "class User; end; $zeitwerk_integration_test_user = true"
app_file "app/models/post.rb", "class Post; end; $zeitwerk_integration_test_post = true"
2019-02-11 15:44:25 -05:00
boot("production")
assert $zeitwerk_integration_test_user
assert $zeitwerk_integration_test_post
end
test "eager loading loads the application code if invoked manually too (regression test)" do
$zeitwerk_integration_test_user = false
$zeitwerk_integration_test_post = false
app_file "app/models/user.rb", "class User; end; $zeitwerk_integration_test_user = true"
app_file "app/models/post.rb", "class Post; end; $zeitwerk_integration_test_post = true"
boot
# Preconditions.
2020-01-07 15:41:33 -05:00
assert_not $zeitwerk_integration_test_user
assert_not $zeitwerk_integration_test_post
Rails.application.eager_load!
# Postconditions.
assert $zeitwerk_integration_test_user
assert $zeitwerk_integration_test_post
end
2019-04-07 06:30:34 -04:00
test "reloading is enabled if config.cache_classes is false" do
boot
assert Rails.autoloaders.main.reloading_enabled?
assert_not Rails.autoloaders.once.reloading_enabled?
end
test "reloading is disabled if config.cache_classes is true" do
boot("production")
assert_not Rails.autoloaders.main.reloading_enabled?
assert_not Rails.autoloaders.once.reloading_enabled?
end
test "eager loading loads code in engines" do
$test_blog_engine_eager_loaded = false
engine("blog") do |bukkit|
bukkit.write("lib/blog.rb", "class BlogEngine < Rails::Engine; end")
bukkit.write("app/models/post.rb", "Post = $test_blog_engine_eager_loaded = true")
end
boot("production")
assert $test_blog_engine_eager_loaded
end
2019-02-11 15:44:25 -05:00
test "eager loading loads anything managed by Zeitwerk" do
2019-02-12 06:07:22 -05:00
$zeitwerk_integration_test_user = false
2019-02-11 15:44:25 -05:00
app_file "app/models/user.rb", "class User; end; $zeitwerk_integration_test_user = true"
$zeitwerk_integration_test_extras = false
app_dir "extras"
app_file "extras/webhook_hacks.rb", "WebhookHacks = 1; $zeitwerk_integration_test_extras = true"
require "zeitwerk"
autoloader = Zeitwerk::Loader.new
autoloader.push_dir("#{app_path}/extras")
autoloader.setup
boot("production")
assert $zeitwerk_integration_test_user
assert $zeitwerk_integration_test_extras
end
test "autoload directories not present in eager load paths are not eager loaded" do
$zeitwerk_integration_test_user = false
app_file "app/models/user.rb", "class User; end; $zeitwerk_integration_test_user = true"
$zeitwerk_integration_test_lib = false
app_dir "lib"
app_file "lib/webhook_hacks.rb", "WebhookHacks = 1; $zeitwerk_integration_test_lib = true"
$zeitwerk_integration_test_extras = false
app_dir "extras"
app_file "extras/websocket_hacks.rb", "WebsocketHacks = 1; $zeitwerk_integration_test_extras = true"
add_to_config "config.autoload_paths << '#{app_path}/lib'"
add_to_config "config.autoload_once_paths << '#{app_path}/extras'"
boot("production")
assert $zeitwerk_integration_test_user
2019-04-02 19:40:15 -04:00
assert_not $zeitwerk_integration_test_lib
assert_not $zeitwerk_integration_test_extras
assert WebhookHacks
assert WebsocketHacks
assert $zeitwerk_integration_test_lib
assert $zeitwerk_integration_test_extras
end
test "autoload_paths not in autoload_once_paths are set as root dirs of main, and in the same order" do
2019-02-11 15:44:25 -05:00
boot
existing_autoload_paths = \
deps.autoload_paths.select { |dir| File.directory?(dir) } -
deps.autoload_once_paths
assert_equal existing_autoload_paths, Rails.autoloaders.main.dirs
end
test "autoload_once_paths go to the once autoloader, and in the same order" do
extras = %w(e1 e2 e3)
extras.each do |extra|
app_dir extra
add_to_config %(config.autoload_once_paths << "\#{Rails.root}/#{extra}")
end
boot
extras = extras.map { |extra| "#{app_path}/#{extra}" }
extras.each do |extra|
assert_not_includes Rails.autoloaders.main.dirs, extra
end
e1_index = Rails.autoloaders.once.dirs.index(extras.first)
assert e1_index
assert_equal extras, Rails.autoloaders.once.dirs.slice(e1_index, extras.length)
2019-02-11 15:44:25 -05:00
end
test "clear reloads the main autoloader, and does not reload the once one" do
boot
$zeitwerk_integration_reload_test = []
main_autoloader = Rails.autoloaders.main
def main_autoloader.reload
$zeitwerk_integration_reload_test << :main_autoloader
2019-02-11 15:44:25 -05:00
super
end
once_autoloader = Rails.autoloaders.once
2019-02-11 15:44:25 -05:00
def once_autoloader.reload
$zeitwerk_integration_reload_test << :once_autoloader
super
end
ActiveSupport::Dependencies.clear
assert_equal %i(main_autoloader), $zeitwerk_integration_reload_test
2019-02-11 15:44:25 -05:00
end
test "reloading invokes before_remove_const" do
$before_remove_const_invoked = false
app_file "app/models/foo.rb", <<~RUBY
# While the most common use case is classes/modules, the contract does not
# require values to be so. Let's weaken the test down to Object.new.
Foo = Object.new
def Foo.before_remove_const
$before_remove_const_invoked = true
end
RUBY
app_file "app/models/bar.rb", <<~RUBY
# This object does not implement before_remove_const. We define it to make
# sure reloading does not raise. That is, it does not blindly invoke the
# hook on all unloaded objects.
Bar = Object.new
RUBY
boot
assert Foo
assert Bar
ActiveSupport::Dependencies.clear
assert $before_remove_const_invoked
end
test "reloading clears autoloaded tracked classes" do
eval <<~RUBY
class Parent
extend ActiveSupport::DescendantsTracker
end
RUBY
app_file "app/models/child.rb", <<~RUBY
class Child < #{self.class.name}::Parent
end
RUBY
app_file "app/models/grandchild.rb", <<~RUBY
class Grandchild < Child
end
RUBY
boot
assert Grandchild
# Preconditions, we add some redundancy about descendants tracking.
assert_equal Set[Child, Grandchild], ActiveSupport::Dependencies._autoloaded_tracked_classes
assert_equal [Child, Grandchild], Parent.descendants
Rails.application.reloader.reload!
assert_empty ActiveSupport::Dependencies._autoloaded_tracked_classes
assert_equal [], Parent.descendants
end
2019-02-21 04:26:36 -05:00
test "autoloaders.logger=" do
boot
logger = ->(_msg) { }
Rails.autoloaders.logger = logger
Rails.autoloaders.each do |autoloader|
assert_same logger, autoloader.logger
2019-02-21 04:26:36 -05:00
end
Rails.autoloaders.logger = Rails.logger
Rails.autoloaders.each do |autoloader|
assert_same Rails.logger, autoloader.logger
2019-02-21 04:26:36 -05:00
end
Rails.autoloaders.logger = nil
Rails.autoloaders.each do |autoloader|
assert_nil autoloader.logger
end
end
2019-08-13 12:14:50 -04:00
test "autoloaders.log!" do
app_file "extras/utils.rb", "module Utils; end"
add_to_config %(config.autoload_once_paths << "\#{Rails.root}/extras")
add_to_config "Rails.autoloaders.log!"
out, _err = capture_io { boot }
assert_match %r/^Zeitwerk@rails.main: autoload set for ApplicationRecord/, out
assert_match %r/^Zeitwerk@rails.once: autoload set for Utils/, out
end
2019-02-11 15:44:25 -05:00
end