diff options
Diffstat (limited to 'railties/test')
53 files changed, 1727 insertions, 725 deletions
diff --git a/railties/test/application/bin_setup_test.rb b/railties/test/application/bin_setup_test.rb index d02100d94c..a952d2466b 100644 --- a/railties/test/application/bin_setup_test.rb +++ b/railties/test/application/bin_setup_test.rb @@ -45,6 +45,8 @@ module ApplicationTests output.sub!(/^Resolving dependencies\.\.\.\n/, "") # Suppress Bundler platform warnings from output output.gsub!(/^The dependency .* will be unused .*\.\n/, "") + # Ignore warnings such as `Psych.safe_load is deprecated` + output.gsub!(/^warning:\s.*\n/, "") assert_equal(<<~OUTPUT, output) == Installing dependencies == diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 9b01d42b1e..73773602a3 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -331,7 +331,7 @@ module ApplicationTests assert_not_includes Post.instance_methods, :title end - test "eager loads attribute methods in production" do + test "does not eager load attribute methods in production when the schema cache is empty" do app_file "app/models/post.rb", <<-RUBY class Post < ActiveRecord::Base end @@ -354,9 +354,71 @@ module ApplicationTests app "production" + assert_not_includes Post.instance_methods, :title + end + + test "eager loads attribute methods in production when the schema cache is populated" do + app_file "app/models/post.rb", <<-RUBY + class Post < ActiveRecord::Base + end + RUBY + + app_file "config/initializers/active_record.rb", <<-RUBY + ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") + ActiveRecord::Migration.verbose = false + ActiveRecord::Schema.define(version: 1) do + create_table :posts do |t| + t.string :title + end + end + RUBY + + add_to_config <<-RUBY + config.eager_load = true + config.cache_classes = true + RUBY + + app_file "config/initializers/schema_cache.rb", <<-RUBY + ActiveRecord::Base.connection.schema_cache.add("posts") + RUBY + + app "production" + assert_includes Post.instance_methods, :title end + test "does not attempt to eager load attribute methods for models that aren't connected" do + app_file "app/models/post.rb", <<-RUBY + class Post < ActiveRecord::Base + end + RUBY + + app_file "config/initializers/active_record.rb", <<-RUBY + ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") + ActiveRecord::Migration.verbose = false + ActiveRecord::Schema.define(version: 1) do + create_table :posts do |t| + t.string :title + end + end + RUBY + + add_to_config <<-RUBY + config.eager_load = true + config.cache_classes = true + RUBY + + app_file "app/models/comment.rb", <<-RUBY + class Comment < ActiveRecord::Base + establish_connection(adapter: "mysql2", database: "does_not_exist") + end + RUBY + + assert_nothing_raised do + app "production" + end + end + test "initialize an eager loaded, cache classes app" do add_to_config <<-RUBY config.eager_load = true @@ -534,45 +596,6 @@ module ApplicationTests assert_equal "some_value", verifier.verify(message) end - test "application message verifier can be used when the key_generator is ActiveSupport::LegacyKeyGenerator" do - app_file "config/initializers/secret_token.rb", <<-RUBY - Rails.application.credentials.secret_key_base = nil - Rails.application.config.secret_token = "b3c631c314c0bbca50c1b2843150fe33" - RUBY - - app "production" - - assert_kind_of ActiveSupport::LegacyKeyGenerator, Rails.application.key_generator - message = app.message_verifier(:sensitive_value).generate("some_value") - assert_equal "some_value", Rails.application.message_verifier(:sensitive_value).verify(message) - end - - test "config.secret_token is deprecated" do - app_file "config/initializers/secret_token.rb", <<-RUBY - Rails.application.config.secret_token = "b3c631c314c0bbca50c1b2843150fe33" - RUBY - - app "production" - - assert_deprecated(/secret_token/) do - app.secrets - end - end - - test "secrets.secret_token is deprecated" do - app_file "config/secrets.yml", <<-YAML - production: - secret_token: "b3c631c314c0bbca50c1b2843150fe33" - YAML - - app "production" - - assert_deprecated(/secret_token/) do - app.secrets - end - end - - test "raises when secret_key_base is blank" do app_file "config/initializers/secret_token.rb", <<-RUBY Rails.application.credentials.secret_key_base = nil @@ -594,20 +617,6 @@ module ApplicationTests end end - test "prefer secrets.secret_token over config.secret_token" do - app_file "config/initializers/secret_token.rb", <<-RUBY - Rails.application.config.secret_token = "" - RUBY - app_file "config/secrets.yml", <<-YAML - development: - secret_token: 3b7cd727ee24e8444053437c36cc66c3 - YAML - - app "development" - - assert_equal "3b7cd727ee24e8444053437c36cc66c3", app.secrets.secret_token - end - test "application verifier can build different verifiers" do make_basic_app do |application| application.credentials.secret_key_base = "b3c631c314c0bbca50c1b2843150fe33" @@ -649,22 +658,6 @@ module ApplicationTests assert_equal "3b7cd727ee24e8444053437c36cc66c3", app.secrets.secret_key_base end - test "config.secret_token over-writes a blank secrets.secret_token" do - app_file "config/initializers/secret_token.rb", <<-RUBY - Rails.application.config.secret_token = "b3c631c314c0bbca50c1b2843150fe33" - RUBY - app_file "config/secrets.yml", <<-YAML - development: - secret_key_base: - secret_token: - YAML - - app "development" - - assert_equal "b3c631c314c0bbca50c1b2843150fe33", app.secrets.secret_token - assert_equal "b3c631c314c0bbca50c1b2843150fe33", app.config.secret_token - end - test "custom secrets saved in config/secrets.yml are loaded in app secrets" do app_file "config/secrets.yml", <<-YAML development: @@ -727,19 +720,6 @@ module ApplicationTests assert_equal "iaminallyoursecretkeybase", app.secrets.secret_key_base end - test "uses ActiveSupport::LegacyKeyGenerator as app.key_generator when secrets.secret_key_base is blank" do - app_file "config/initializers/secret_token.rb", <<-RUBY - Rails.application.credentials.secret_key_base = nil - Rails.application.config.secret_token = "b3c631c314c0bbca50c1b2843150fe33" - RUBY - - app "production" - - assert_equal "b3c631c314c0bbca50c1b2843150fe33", app.config.secret_token - assert_nil app.credentials.secret_key_base - assert_kind_of ActiveSupport::LegacyKeyGenerator, app.key_generator - end - test "that nested keys are symbolized the same as parents for hashes more than one level deep" do app_file "config/secrets.yml", <<-YAML development: @@ -1177,6 +1157,34 @@ module ApplicationTests end end + test "autoloaders" do + app "development" + + config = Rails.application.config + assert Rails.autoloaders.zeitwerk_enabled? + assert_instance_of Zeitwerk::Loader, Rails.autoloaders.main + assert_equal "rails.main", Rails.autoloaders.main.tag + assert_instance_of Zeitwerk::Loader, Rails.autoloaders.once + assert_equal "rails.once", Rails.autoloaders.once.tag + assert_equal [Rails.autoloaders.main, Rails.autoloaders.once], Rails.autoloaders.to_a + + config.autoloader = :classic + assert_not Rails.autoloaders.zeitwerk_enabled? + assert_nil Rails.autoloaders.main + assert_nil Rails.autoloaders.once + assert_equal 0, Rails.autoloaders.count + + config.autoloader = :zeitwerk + assert Rails.autoloaders.zeitwerk_enabled? + assert_instance_of Zeitwerk::Loader, Rails.autoloaders.main + assert_equal "rails.main", Rails.autoloaders.main.tag + assert_instance_of Zeitwerk::Loader, Rails.autoloaders.once + assert_equal "rails.once", Rails.autoloaders.once.tag + assert_equal [Rails.autoloaders.main, Rails.autoloaders.once], Rails.autoloaders.to_a + + assert_raises(ArgumentError) { config.autoloader = :unknown } + end + test "config.action_view.cache_template_loading with cache_classes default" do add_to_config "config.cache_classes = true" @@ -1493,14 +1501,12 @@ module ApplicationTests end test "config.session_store with :active_record_store with activerecord-session_store gem" do - begin - make_basic_app do |application| - ActionDispatch::Session::ActiveRecordStore = Class.new(ActionDispatch::Session::CookieStore) - application.config.session_store :active_record_store - end - ensure - ActionDispatch::Session.send :remove_const, :ActiveRecordStore + make_basic_app do |application| + ActionDispatch::Session::ActiveRecordStore = Class.new(ActionDispatch::Session::CookieStore) + application.config.session_store :active_record_store end + ensure + ActionDispatch::Session.send :remove_const, :ActiveRecordStore end test "config.session_store with :active_record_store without activerecord-session_store gem" do @@ -1663,6 +1669,14 @@ module ApplicationTests assert_kind_of Hash, Rails.application.config.database_configuration end + test "autoload paths do not include asset paths" do + app "development" + ActiveSupport::Dependencies.autoload_paths.each do |path| + assert_not_operator path, :ends_with?, "app/assets" + assert_not_operator path, :ends_with?, "app/javascript" + end + end + test "raises with proper error message if no database configuration found" do FileUtils.rm("#{app_path}/config/database.yml") err = assert_raises RuntimeError do @@ -1728,7 +1742,7 @@ module ApplicationTests assert_equal true, Rails.application.config.action_mailer.show_previews end - test "config_for loads custom configuration from yaml files" do + test "config_for loads custom configuration from yaml accessible as symbol or string" do app_file "config/custom.yml", <<-RUBY development: foo: 'bar' @@ -1740,13 +1754,16 @@ module ApplicationTests app "development" + assert_equal "bar", Rails.application.config.my_custom_config[:foo] assert_equal "bar", Rails.application.config.my_custom_config["foo"] end - test "config_for loads custom configuration from yaml accessible as symbol" do + test "config_for loads nested custom configuration from yaml as symbol keys" do app_file "config/custom.yml", <<-RUBY development: - foo: 'bar' + foo: + bar: + baz: 1 RUBY add_to_config <<-RUBY @@ -1755,13 +1772,15 @@ module ApplicationTests app "development" - assert_equal "bar", Rails.application.config.my_custom_config[:foo] + assert_equal 1, Rails.application.config.my_custom_config[:foo][:bar][:baz] end - test "config_for loads custom configuration from yaml accessible as method" do + test "config_for loads nested custom configuration from yaml with deprecated non-symbol access" do app_file "config/custom.yml", <<-RUBY development: - foo: 'bar' + foo: + bar: + baz: 1 RUBY add_to_config <<-RUBY @@ -1770,15 +1789,17 @@ module ApplicationTests app "development" - assert_equal "bar", Rails.application.config.my_custom_config.foo + assert_deprecated do + assert_equal 1, Rails.application.config.my_custom_config["foo"]["bar"]["baz"] + end end - test "config_for loads nested custom configuration from yaml as symbol keys" do + test "config_for loads nested custom configuration inside array from yaml with deprecated non-symbol access" do app_file "config/custom.yml", <<-RUBY development: foo: bar: - baz: 1 + - baz: 1 RUBY add_to_config <<-RUBY @@ -1787,7 +1808,117 @@ module ApplicationTests app "development" - assert_equal 1, Rails.application.config.my_custom_config.foo[:bar][:baz] + config = Rails.application.config.my_custom_config + assert_instance_of Rails::Application::NonSymbolAccessDeprecatedHash, config[:foo][:bar].first + + assert_deprecated do + assert_equal 1, config[:foo][:bar].first["baz"] + end + end + + test "config_for makes all hash methods available" do + app_file "config/custom.yml", <<-RUBY + development: + foo: 0 + bar: + baz: 1 + RUBY + + add_to_config <<-RUBY + config.my_custom_config = config_for('custom') + RUBY + + app "development" + + actual = Rails.application.config.my_custom_config + + assert_equal({ foo: 0, bar: { baz: 1 } }, actual) + assert_equal([ :foo, :bar ], actual.keys) + assert_equal([ 0, baz: 1], actual.values) + assert_equal({ foo: 0, bar: { baz: 1 } }, actual.to_h) + assert_equal(0, actual[:foo]) + assert_equal({ baz: 1 }, actual[:bar]) + end + + test "config_for generates deprecation notice when nested hash methods are called with non-symbols" do + app_file "config/custom.yml", <<-RUBY + development: + foo: + bar: 1 + baz: 2 + qux: + boo: 3 + RUBY + + app "development" + + actual = Rails.application.config_for("custom")[:foo] + + # slice + assert_deprecated do + assert_equal({ bar: 1, baz: 2 }, actual.slice("bar", "baz")) + end + + # except + assert_deprecated do + assert_equal({ qux: { boo: 3 } }, actual.except("bar", "baz")) + end + + # dig + assert_deprecated do + assert_equal(3, actual.dig("qux", "boo")) + end + + # fetch - hit + assert_deprecated do + assert_equal(1, actual.fetch("bar", 0)) + end + + # fetch - miss + assert_deprecated do + assert_equal(0, actual.fetch("does-not-exist", 0)) + end + + # fetch_values + assert_deprecated do + assert_equal([1, 2], actual.fetch_values("bar", "baz")) + end + + # key? - hit + assert_deprecated do + assert(actual.key?("bar")) + end + + # key? - miss + assert_deprecated do + assert_not(actual.key?("does-not-exist")) + end + + # slice! + actual = Rails.application.config_for("custom")[:foo] + + assert_deprecated do + slice = actual.slice!("bar", "baz") + assert_equal({ bar: 1, baz: 2 }, actual) + assert_equal({ qux: { boo: 3 } }, slice) + end + + # extract! + actual = Rails.application.config_for("custom")[:foo] + + assert_deprecated do + extracted = actual.extract!("bar", "baz") + assert_equal({ bar: 1, baz: 2 }, extracted) + assert_equal({ qux: { boo: 3 } }, actual) + end + + # except! + actual = Rails.application.config_for("custom")[:foo] + + assert_deprecated do + actual.except!("bar", "baz") + assert_equal({ qux: { boo: 3 } }, actual) + end end test "config_for uses the Pathname object if it is provided" do @@ -1802,7 +1933,7 @@ module ApplicationTests app "development" - assert_equal "custom key", Rails.application.config.my_custom_config["key"] + assert_equal "custom key", Rails.application.config.my_custom_config[:key] end test "config_for raises an exception if the file does not exist" do @@ -1832,8 +1963,29 @@ module ApplicationTests assert_equal({}, Rails.application.config.my_custom_config) end - test "config_for with empty file returns an empty hash" do + test "config_for implements shared configuration as secrets case found" do app_file "config/custom.yml", <<-RUBY + shared: + foo: :bar + test: + foo: :baz + RUBY + + add_to_config <<-RUBY + config.my_custom_config = config_for('custom') + RUBY + + app "test" + + assert_equal(:baz, Rails.application.config.my_custom_config[:foo]) + end + + test "config_for implements shared configuration as secrets case not found" do + app_file "config/custom.yml", <<-RUBY + shared: + foo: :bar + test: + foo: :baz RUBY add_to_config <<-RUBY @@ -1842,40 +1994,45 @@ module ApplicationTests app "development" - assert_equal({}, Rails.application.config.my_custom_config) + assert_equal(:bar, Rails.application.config.my_custom_config[:foo]) end - test "default SQLite3Adapter.represent_boolean_as_integer for 5.1 is false" do - remove_from_config '.*config\.load_defaults.*\n' + test "config_for with empty file returns an empty hash" do + app_file "config/custom.yml", <<-RUBY + RUBY - app_file "app/models/post.rb", <<-RUBY - class Post < ActiveRecord::Base - end + add_to_config <<-RUBY + config.my_custom_config = config_for('custom') RUBY app "development" - force_lazy_load_hooks { Post } - assert_not ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer + assert_equal({}, Rails.application.config.my_custom_config) end - test "default SQLite3Adapter.represent_boolean_as_integer for new installs is true" do + test "represent_boolean_as_integer is deprecated" do + remove_from_config '.*config\.load_defaults.*\n' + + app_file "config/initializers/new_framework_defaults_6_0.rb", <<-RUBY + Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true + RUBY + app_file "app/models/post.rb", <<-RUBY class Post < ActiveRecord::Base end RUBY app "development" - force_lazy_load_hooks { Post } - - assert ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer + assert_deprecated do + force_lazy_load_hooks { Post } + end end - test "represent_boolean_as_integer should be able to set via config.active_record.sqlite3.represent_boolean_as_integer" do + test "represent_boolean_as_integer raises when the value is false" do remove_from_config '.*config\.load_defaults.*\n' app_file "config/initializers/new_framework_defaults_6_0.rb", <<-RUBY - Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true + Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = false RUBY app_file "app/models/post.rb", <<-RUBY @@ -1884,9 +2041,9 @@ module ApplicationTests RUBY app "development" - force_lazy_load_hooks { Post } - - assert ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer + assert_raises(RuntimeError) do + force_lazy_load_hooks { Post } + end end test "config_for containing ERB tags should evaluate" do @@ -1901,7 +2058,7 @@ module ApplicationTests app "development" - assert_equal "custom key", Rails.application.config.my_custom_config["key"] + assert_equal "custom key", Rails.application.config.my_custom_config[:key] end test "config_for with syntax error show a more descriptive exception" do @@ -1934,7 +2091,7 @@ module ApplicationTests RUBY require "#{app_path}/config/environment" - assert_equal "unicorn", Rails.application.config.my_custom_config["key"] + assert_equal "unicorn", Rails.application.config.my_custom_config[:key] end test "api_only is false by default" do @@ -2088,7 +2245,9 @@ module ApplicationTests test "ActionView::Template.finalize_compiled_template_methods is true by default" do app "test" - assert_equal true, ActionView::Template.finalize_compiled_template_methods + assert_deprecated do + ActionView::Template.finalize_compiled_template_methods + end end test "ActionView::Template.finalize_compiled_template_methods can be configured via config.action_view.finalize_compiled_template_methods" do @@ -2100,7 +2259,162 @@ module ApplicationTests app "test" - assert_equal false, ActionView::Template.finalize_compiled_template_methods + assert_deprecated do + ActionView::Template.finalize_compiled_template_methods + end + end + + test "ActiveJob::Base.return_false_on_aborted_enqueue is true by default" do + app "development" + + assert_equal true, ActiveJob::Base.return_false_on_aborted_enqueue + end + + test "ActiveJob::Base.return_false_on_aborted_enqueue is false in the 5.x defaults" do + remove_from_config '.*config\.load_defaults.*\n' + add_to_config 'config.load_defaults "5.2"' + + app "development" + + assert_equal false, ActiveJob::Base.return_false_on_aborted_enqueue + end + + test "ActiveJob::Base.return_false_on_aborted_enqueue can be configured in the new framework defaults" do + remove_from_config '.*config\.load_defaults.*\n' + + app_file "config/initializers/new_framework_defaults_6_0.rb", <<-RUBY + Rails.application.config.active_job.return_false_on_aborted_enqueue = true + RUBY + + app "development" + + assert_equal true, ActiveJob::Base.return_false_on_aborted_enqueue + end + + test "ActiveStorage.queues[:analysis] is :active_storage_analysis by default" do + app "development" + + assert_equal :active_storage_analysis, ActiveStorage.queues[:analysis] + end + + test "ActiveStorage.queues[:analysis] is nil without Rails 6 defaults" do + remove_from_config '.*config\.load_defaults.*\n' + + app "development" + + assert_nil ActiveStorage.queues[:analysis] + end + + test "ActiveStorage.queues[:purge] is :active_storage_purge by default" do + app "development" + + assert_equal :active_storage_purge, ActiveStorage.queues[:purge] + end + + test "ActiveStorage.queues[:purge] is nil without Rails 6 defaults" do + remove_from_config '.*config\.load_defaults.*\n' + + app "development" + + assert_nil ActiveStorage.queues[:purge] + end + + test "ActionMailbox.logger is Rails.logger by default" do + app "development" + + assert_equal Rails.logger, ActionMailbox.logger + end + + test "ActionMailbox.logger can be configured" do + app_file "lib/my_logger.rb", <<-RUBY + require "logger" + class MyLogger < ::Logger + end + RUBY + + add_to_config <<-RUBY + require "my_logger" + config.action_mailbox.logger = MyLogger.new(STDOUT) + RUBY + + app "development" + + assert_equal "MyLogger", ActionMailbox.logger.class.name + end + + test "ActionMailbox.incinerate_after is 30.days by default" do + app "development" + + assert_equal 30.days, ActionMailbox.incinerate_after + end + + test "ActionMailbox.incinerate_after can be configured" do + add_to_config <<-RUBY + config.action_mailbox.incinerate_after = 14.days + RUBY + + app "development" + + assert_equal 14.days, ActionMailbox.incinerate_after + end + + test "ActionMailbox.queues[:incineration] is :action_mailbox_incineration by default" do + app "development" + + assert_equal :action_mailbox_incineration, ActionMailbox.queues[:incineration] + end + + test "ActionMailbox.queues[:incineration] can be configured" do + add_to_config <<-RUBY + config.action_mailbox.queues.incineration = :another_queue + RUBY + + app "development" + + assert_equal :another_queue, ActionMailbox.queues[:incineration] + end + + test "ActionMailbox.queues[:routing] is :action_mailbox_routing by default" do + app "development" + + assert_equal :action_mailbox_routing, ActionMailbox.queues[:routing] + end + + test "ActionMailbox.queues[:routing] can be configured" do + add_to_config <<-RUBY + config.action_mailbox.queues.routing = :another_queue + RUBY + + app "development" + + assert_equal :another_queue, ActionMailbox.queues[:routing] + end + + test "ActionMailer::Base.delivery_job is ActionMailer::MailDeliveryJob by default" do + app "development" + + assert_equal ActionMailer::MailDeliveryJob, ActionMailer::Base.delivery_job + end + + test "ActionMailer::Base.delivery_job is ActionMailer::DeliveryJob in the 5.x defaults" do + remove_from_config '.*config\.load_defaults.*\n' + add_to_config 'config.load_defaults "5.2"' + + app "development" + + assert_equal ActionMailer::DeliveryJob, ActionMailer::Base.delivery_job + end + + test "ActionMailer::Base.delivery_job can be configured in the new framework defaults" do + remove_from_config '.*config\.load_defaults.*\n' + + app_file "config/initializers/new_framework_defaults_6_0.rb", <<-RUBY + Rails.application.config.action_mailer.delivery_job = "ActionMailer::MailDeliveryJob" + RUBY + + app "development" + + assert_equal ActionMailer::MailDeliveryJob, ActionMailer::Base.delivery_job end test "ActiveRecord::Base.filter_attributes should equal to filter_parameters" do @@ -2109,7 +2423,7 @@ module ApplicationTests RUBY app "development" assert_equal [ :password, :credit_card_number ], Rails.application.config.filter_parameters - assert_equal [ "password", "credit_card_number" ].to_set, ActiveRecord::Base.filter_attributes + assert_equal [ :password, :credit_card_number ], ActiveRecord::Base.filter_attributes end test "ActiveStorage.routes_prefix can be configured via config.active_storage.routes_prefix" do @@ -2130,6 +2444,11 @@ module ApplicationTests MESSAGE end + test "hosts include .localhost in development" do + app "development" + assert_includes Rails.application.config.hosts, ".localhost" + end + private def force_lazy_load_hooks yield # Tasty clarifying sugar, homie! We only need to reference a constant to load it. diff --git a/railties/test/application/console_test.rb b/railties/test/application/console_test.rb index 29f8b1e3d9..b6270525f0 100644 --- a/railties/test/application/console_test.rb +++ b/railties/test/application/console_test.rb @@ -25,7 +25,7 @@ class ConsoleTest < ActiveSupport::TestCase end def test_app_method_should_return_integration_session - TestHelpers::Rack.send :remove_method, :app + TestHelpers::Rack.remove_method :app load_environment console_session = irb_context.app assert_instance_of ActionDispatch::Integration::Session, console_session @@ -149,7 +149,7 @@ class FullStackConsoleTest < ActiveSupport::TestCase end def test_environment_option_and_irb_option - spawn_console("test -- --verbose") + spawn_console("-e test -- --verbose") write_prompt "a = 1", "a = 1" write_prompt "puts Rails.env", "puts Rails.env\r\ntest" diff --git a/railties/test/application/credentials_test.rb b/railties/test/application/credentials_test.rb new file mode 100644 index 0000000000..2f6b109b50 --- /dev/null +++ b/railties/test/application/credentials_test.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +require "isolation/abstract_unit" +require "env_helpers" + +class Rails::CredentialsTest < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation, EnvHelpers + + setup :build_app + teardown :teardown_app + + test "reads credentials from environment specific path" do + write_credentials_override(:production) + + app("production") + + assert_equal "revealed", Rails.application.credentials.mystery + end + + test "reads credentials from customized path and key" do + write_credentials_override(:staging) + add_to_env_config("production", "config.credentials.content_path = config.root.join('config/credentials/staging.yml.enc')") + add_to_env_config("production", "config.credentials.key_path = config.root.join('config/credentials/staging.key')") + + app("production") + + assert_equal "revealed", Rails.application.credentials.mystery + end + + test "reads credentials using environment variable key" do + write_credentials_override(:production, with_key: false) + + switch_env("RAILS_MASTER_KEY", credentials_key) do + app("production") + + assert_equal "revealed", Rails.application.credentials.mystery + end + end + + private + def write_credentials_override(name, with_key: true) + Dir.chdir(app_path) do + Dir.mkdir "config/credentials" + File.write "config/credentials/#{name}.key", credentials_key if with_key + + # secret_key_base: secret + # mystery: revealed + File.write "config/credentials/#{name}.yml.enc", + "vgvKu4MBepIgZ5VHQMMPwnQNsLlWD9LKmJHu3UA/8yj6x+3fNhz3DwL9brX7UA==--qLdxHP6e34xeTAiI--nrcAsleXuo9NqiEuhntAhw==" + end + end + + def credentials_key + "2117e775dc2024d4f49ddf3aeb585919" + end +end diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index 1530ea82d6..3cd4b8fe33 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -230,35 +230,31 @@ module ApplicationTests end test "active record establish_connection uses Rails.env if DATABASE_URL is not set" do - begin - require "#{app_path}/config/environment" - orig_database_url = ENV.delete("DATABASE_URL") - orig_rails_env, Rails.env = Rails.env, "development" - ActiveRecord::Base.establish_connection - assert ActiveRecord::Base.connection - assert_match(/#{ActiveRecord::Base.configurations[Rails.env]['database']}/, ActiveRecord::Base.connection_config[:database]) - ensure - ActiveRecord::Base.remove_connection - ENV["DATABASE_URL"] = orig_database_url if orig_database_url - Rails.env = orig_rails_env if orig_rails_env - end + require "#{app_path}/config/environment" + orig_database_url = ENV.delete("DATABASE_URL") + orig_rails_env, Rails.env = Rails.env, "development" + ActiveRecord::Base.establish_connection + assert ActiveRecord::Base.connection + assert_match(/#{ActiveRecord::Base.configurations[Rails.env]['database']}/, ActiveRecord::Base.connection_config[:database]) + ensure + ActiveRecord::Base.remove_connection + ENV["DATABASE_URL"] = orig_database_url if orig_database_url + Rails.env = orig_rails_env if orig_rails_env end test "active record establish_connection uses DATABASE_URL even if Rails.env is set" do - begin - require "#{app_path}/config/environment" - orig_database_url = ENV.delete("DATABASE_URL") - orig_rails_env, Rails.env = Rails.env, "development" - database_url_db_name = "db/database_url_db.sqlite3" - ENV["DATABASE_URL"] = "sqlite3:#{database_url_db_name}" - ActiveRecord::Base.establish_connection - assert ActiveRecord::Base.connection - assert_match(/#{database_url_db_name}/, ActiveRecord::Base.connection_config[:database]) - ensure - ActiveRecord::Base.remove_connection - ENV["DATABASE_URL"] = orig_database_url if orig_database_url - Rails.env = orig_rails_env if orig_rails_env - end + require "#{app_path}/config/environment" + orig_database_url = ENV.delete("DATABASE_URL") + orig_rails_env, Rails.env = Rails.env, "development" + database_url_db_name = "db/database_url_db.sqlite3" + ENV["DATABASE_URL"] = "sqlite3:#{database_url_db_name}" + ActiveRecord::Base.establish_connection + assert ActiveRecord::Base.connection + assert_match(/#{database_url_db_name}/, ActiveRecord::Base.connection_config[:database]) + ensure + ActiveRecord::Base.remove_connection + ENV["DATABASE_URL"] = orig_database_url if orig_database_url + Rails.env = orig_rails_env if orig_rails_env end test "connections checked out during initialization are returned to the pool" do diff --git a/railties/test/application/loading_test.rb b/railties/test/application/loading_test.rb index bfa66770bd..9c98489590 100644 --- a/railties/test/application/loading_test.rb +++ b/railties/test/application/loading_test.rb @@ -34,6 +34,22 @@ class LoadingTest < ActiveSupport::TestCase assert_equal "omg", p.title end + test "constants without a matching file raise NameError" do + app_file "app/models/post.rb", <<-RUBY + class Post + NON_EXISTING_CONSTANT + end + RUBY + + boot_app + + e = assert_raise(NameError) { User } + assert_equal "uninitialized constant #{self.class}::User", e.message + + e = assert_raise(NameError) { Post } + assert_equal "uninitialized constant Post::NON_EXISTING_CONSTANT", e.message + end + test "concerns in app are autoloaded" do app_file "app/controllers/concerns/trackable.rb", <<-CONCERN module Trackable diff --git a/railties/test/application/mailer_previews_test.rb b/railties/test/application/mailer_previews_test.rb index ba186bda44..fb84276b8a 100644 --- a/railties/test/application/mailer_previews_test.rb +++ b/railties/test/application/mailer_previews_test.rb @@ -85,6 +85,7 @@ module ApplicationTests end test "mailer previews are loaded from a custom preview_path" do + app_dir "lib/mailer_previews" add_to_config "config.action_mailer.preview_path = '#{app_path}/lib/mailer_previews'" mailer "notifier", <<-RUBY @@ -254,6 +255,7 @@ module ApplicationTests end test "mailer previews are reloaded from a custom preview_path" do + app_dir "lib/mailer_previews" add_to_config "config.action_mailer.preview_path = '#{app_path}/lib/mailer_previews'" app("development") @@ -818,6 +820,7 @@ module ApplicationTests def build_app super app_file "config/routes.rb", "Rails.application.routes.draw do; end" + app_dir "test/mailers/previews" end def mailer(name, contents) diff --git a/railties/test/application/middleware/remote_ip_test.rb b/railties/test/application/middleware/remote_ip_test.rb index 83cf8a27f7..515b32080e 100644 --- a/railties/test/application/middleware/remote_ip_test.rb +++ b/railties/test/application/middleware/remote_ip_test.rb @@ -12,7 +12,9 @@ module ApplicationTests remote_ip = nil env = Rack::MockRequest.env_for("/").merge(env).merge!( "action_dispatch.show_exceptions" => false, - "action_dispatch.key_generator" => ActiveSupport::LegacyKeyGenerator.new("b3c631c314c0bbca50c1b2843150fe33") + "action_dispatch.key_generator" => ActiveSupport::CachingKeyGenerator.new( + ActiveSupport::KeyGenerator.new("b3c631c314c0bbca50c1b2843150fe33", iterations: 1000) + ) ) endpoint = Proc.new do |e| diff --git a/railties/test/application/middleware/session_test.rb b/railties/test/application/middleware/session_test.rb index b25e56b625..479615c133 100644 --- a/railties/test/application/middleware/session_test.rb +++ b/railties/test/application/middleware/session_test.rb @@ -215,8 +215,6 @@ module ApplicationTests RUBY add_to_config <<-RUBY - secrets.secret_token = "3b7cd727ee24e8444053437c36cc66c4" - # Enable AEAD cookies config.action_dispatch.use_authenticated_cookie_encryption = true RUBY @@ -238,68 +236,6 @@ module ApplicationTests assert_equal 1, encryptor.decrypt_and_verify(last_response.body, purpose: "cookie._myapp_session")["foo"] end - test "session upgrading signature to encryption cookie store upgrades session to encrypted mode" do - app_file "config/routes.rb", <<-RUBY - Rails.application.routes.draw do - get ':controller(/:action)' - end - RUBY - - controller :foo, <<-RUBY - class FooController < ActionController::Base - def write_raw_session - # {"session_id"=>"1965d95720fffc123941bdfb7d2e6870", "foo"=>1} - cookies[:_myapp_session] = "BAh7B0kiD3Nlc3Npb25faWQGOgZFRkkiJTE5NjVkOTU3MjBmZmZjMTIzOTQxYmRmYjdkMmU2ODcwBjsAVEkiCGZvbwY7AEZpBg==--315fb9931921a87ae7421aec96382f0294119749" - head :ok - end - - def write_session - session[:foo] = session[:foo] + 1 - head :ok - end - - def read_session - render plain: session[:foo] - end - - def read_encrypted_cookie - render plain: cookies.encrypted[:_myapp_session]['foo'] - end - - def read_raw_cookie - render plain: cookies[:_myapp_session] - end - end - RUBY - - add_to_config <<-RUBY - secrets.secret_token = "3b7cd727ee24e8444053437c36cc66c4" - - # Enable AEAD cookies - config.action_dispatch.use_authenticated_cookie_encryption = true - RUBY - - require "#{app_path}/config/environment" - - get "/foo/write_raw_session" - get "/foo/read_session" - assert_equal "1", last_response.body - - get "/foo/write_session" - get "/foo/read_session" - assert_equal "2", last_response.body - - get "/foo/read_encrypted_cookie" - assert_equal "2", last_response.body - - cipher = "aes-256-gcm" - secret = app.key_generator.generate_key("authenticated encrypted cookie") - encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len(cipher)], cipher: cipher) - - get "/foo/read_raw_cookie" - assert_equal 2, encryptor.decrypt_and_verify(last_response.body, purpose: "cookie._myapp_session")["foo"] - end - test "session upgrading from AES-CBC-HMAC encryption to AES-GCM encryption" do app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do @@ -370,70 +306,6 @@ module ApplicationTests end end - test "session upgrading legacy signed cookies to new signed cookies" do - app_file "config/routes.rb", <<-RUBY - Rails.application.routes.draw do - get ':controller(/:action)' - end - RUBY - - controller :foo, <<-RUBY - class FooController < ActionController::Base - def write_raw_session - # {"session_id"=>"1965d95720fffc123941bdfb7d2e6870", "foo"=>1} - cookies[:_myapp_session] = "BAh7B0kiD3Nlc3Npb25faWQGOgZFRkkiJTE5NjVkOTU3MjBmZmZjMTIzOTQxYmRmYjdkMmU2ODcwBjsAVEkiCGZvbwY7AEZpBg==--315fb9931921a87ae7421aec96382f0294119749" - head :ok - end - - def write_session - session[:foo] = session[:foo] + 1 - head :ok - end - - def read_session - render plain: session[:foo] - end - - def read_signed_cookie - render plain: cookies.signed[:_myapp_session]['foo'] - end - - def read_raw_cookie - render plain: cookies[:_myapp_session] - end - end - RUBY - - add_to_config <<-RUBY - secrets.secret_token = "3b7cd727ee24e8444053437c36cc66c4" - Rails.application.credentials.secret_key_base = nil - RUBY - - begin - old_rails_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "production" - - require "#{app_path}/config/environment" - - get "/foo/write_raw_session" - get "/foo/read_session" - assert_equal "1", last_response.body - - get "/foo/write_session" - get "/foo/read_session" - assert_equal "2", last_response.body - - get "/foo/read_signed_cookie" - assert_equal "2", last_response.body - - verifier = ActiveSupport::MessageVerifier.new(app.secrets.secret_token) - - get "/foo/read_raw_cookie" - assert_equal 2, verifier.verify(last_response.body, purpose: "cookie._myapp_session")["foo"] - ensure - ENV["RAILS_ENV"] = old_rails_env - end - end - test "calling reset_session on request does not trigger an error for API apps" do add_to_config "config.api_only = true" diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index 631f5bac7f..4242daf39a 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -26,6 +26,7 @@ module ApplicationTests assert_equal [ "Webpacker::DevServerProxy", + "ActionDispatch::HostAuthorization", "Rack::Sendfile", "ActionDispatch::Static", "ActionDispatch::Executor", @@ -58,6 +59,7 @@ module ApplicationTests assert_equal [ "Webpacker::DevServerProxy", + "ActionDispatch::HostAuthorization", "Rack::Sendfile", "ActionDispatch::Static", "ActionDispatch::Executor", @@ -140,7 +142,7 @@ module ApplicationTests add_to_config "config.ssl_options = { redirect: { host: 'example.com' } }" boot! - assert_equal [{ redirect: { host: "example.com" } }], Rails.application.middleware[1].args + assert_equal [{ redirect: { host: "example.com" } }], Rails.application.middleware[2].args end test "removing Active Record omits its middleware" do @@ -224,7 +226,7 @@ module ApplicationTests test "insert middleware after" do add_to_config "config.middleware.insert_after Rack::Sendfile, Rack::Config" boot! - assert_equal "Rack::Config", middleware.third + assert_equal "Rack::Config", middleware.fourth end test "unshift middleware" do @@ -236,24 +238,24 @@ module ApplicationTests test "Rails.cache does not respond to middleware" do add_to_config "config.cache_store = :memory_store" boot! - assert_equal "Rack::Runtime", middleware.fifth + assert_equal "Rack::Runtime", middleware[5] end test "Rails.cache does respond to middleware" do boot! - assert_equal "ActiveSupport::Cache::Strategy::LocalCache", middleware.fifth - assert_equal "Rack::Runtime", middleware[5] + assert_equal "ActiveSupport::Cache::Strategy::LocalCache", middleware[5] + assert_equal "Rack::Runtime", middleware[6] end test "insert middleware before" do add_to_config "config.middleware.insert_before Rack::Sendfile, Rack::Config" boot! - assert_equal "Rack::Config", middleware.second + assert_equal "Rack::Config", middleware.third end test "can't change middleware after it's built" do boot! - assert_raise frozen_error_class do + assert_raise FrozenError do app.config.middleware.use Rack::Config end end diff --git a/railties/test/application/multiple_applications_test.rb b/railties/test/application/multiple_applications_test.rb index d6c81c1fe2..f0f1112f6b 100644 --- a/railties/test/application/multiple_applications_test.rb +++ b/railties/test/application/multiple_applications_test.rb @@ -100,30 +100,6 @@ module ApplicationTests assert_nothing_raised { AppTemplate::Application.new } end - def test_initializers_run_on_different_applications_go_to_the_same_class - application1 = AppTemplate::Application.new - run_count = 0 - - AppTemplate::Application.initializer :init0 do - run_count += 1 - end - - application1.initializer :init1 do - run_count += 1 - end - - AppTemplate::Application.new.initializer :init2 do - run_count += 1 - end - - assert_equal 0, run_count, "Without loading the initializers, the count should be 0" - - # Set config.eager_load to false so that an eager_load warning doesn't pop up - AppTemplate::Application.create { config.eager_load = false }.initialize! - - assert_equal 3, run_count, "There should have been three initializers that incremented the count" - end - def test_consoles_run_on_different_applications_go_to_the_same_class run_count = 0 AppTemplate::Application.console { run_count += 1 } @@ -165,12 +141,12 @@ module ApplicationTests app.config.some_setting = "a_different_setting" assert_equal "a_different_setting", app.config.some_setting, "The configuration's some_setting should be set." - new_config = Rails::Application::Configuration.new("root_of_application") + new_config = Rails::Application::Configuration.new(Pathname.new("root_of_application")) new_config.some_setting = "some_setting_dude" app.config = new_config assert_equal "some_setting_dude", app.config.some_setting, "The configuration's some_setting should have changed." - assert_equal "root_of_application", app.config.root, "The root should have changed to the new config's root." + assert_equal "root_of_application", app.config.root.to_s, "The root should have changed to the new config's root." assert_equal new_config, app.config, "The application's config should have changed to the new config." end end diff --git a/railties/test/application/rake/dbs_test.rb b/railties/test/application/rake/dbs_test.rb index 039987ac8c..ba5704c53e 100644 --- a/railties/test/application/rake/dbs_test.rb +++ b/railties/test/application/rake/dbs_test.rb @@ -93,6 +93,8 @@ module ApplicationTests def with_bad_permissions Dir.chdir(app_path) do + skip "Can't avoid permissions as root" if Process.uid.zero? + set_database_url FileUtils.chmod("-w", "db") yield @@ -177,9 +179,10 @@ module ApplicationTests def db_fixtures_load(expected_database) Dir.chdir(app_path) do rails "generate", "model", "book", "title:string" + reload rails "db:migrate", "db:fixtures:load" + assert_match expected_database, ActiveRecord::Base.connection_config[:database] - require "#{app_path}/app/models/book" assert_equal 2, Book.count end end @@ -199,8 +202,9 @@ module ApplicationTests require "#{app_path}/config/environment" rails "generate", "model", "admin::book", "title:string" + reload rails "db:migrate", "db:fixtures:load" - require "#{app_path}/app/models/admin/book" + assert_equal 2, Admin::Book.count end @@ -321,13 +325,12 @@ module ApplicationTests end test "db:setup loads schema and seeds database" do - begin - @old_rails_env = ENV["RAILS_ENV"] - @old_rack_env = ENV["RACK_ENV"] - ENV.delete "RAILS_ENV" - ENV.delete "RACK_ENV" + @old_rails_env = ENV["RAILS_ENV"] + @old_rack_env = ENV["RACK_ENV"] + ENV.delete "RAILS_ENV" + ENV.delete "RACK_ENV" - app_file "db/schema.rb", <<-RUBY + app_file "db/schema.rb", <<-RUBY ActiveRecord::Schema.define(version: "1") do create_table :users do |t| t.string :name @@ -335,16 +338,15 @@ module ApplicationTests end RUBY - app_file "db/seeds.rb", <<-RUBY - puts ActiveRecord::Base.connection_config[:database] - RUBY + app_file "db/seeds.rb", <<-RUBY + puts ActiveRecord::Base.connection_config[:database] + RUBY - database_path = rails("db:setup") - assert_equal "development.sqlite3", File.basename(database_path.strip) - ensure - ENV["RAILS_ENV"] = @old_rails_env - ENV["RACK_ENV"] = @old_rack_env - end + database_path = rails("db:setup") + assert_equal "development.sqlite3", File.basename(database_path.strip) + ensure + ENV["RAILS_ENV"] = @old_rails_env + ENV["RACK_ENV"] = @old_rack_env end test "db:setup sets ar_internal_metadata" do diff --git a/railties/test/application/rake/multi_dbs_test.rb b/railties/test/application/rake/multi_dbs_test.rb index 6478e06250..d676e7486e 100644 --- a/railties/test/application/rake/multi_dbs_test.rb +++ b/railties/test/application/rake/multi_dbs_test.rb @@ -65,6 +65,27 @@ module ApplicationTests end end + def db_migrate_and_schema_cache_dump + Dir.chdir(app_path) do + generate_models_for_animals + rails "db:migrate" + rails "db:schema:cache:dump" + assert File.exist?("db/schema_cache.yml") + assert File.exist?("db/animals_schema_cache.yml") + end + end + + def db_migrate_and_schema_cache_dump_and_schema_cache_clear + Dir.chdir(app_path) do + generate_models_for_animals + rails "db:migrate" + rails "db:schema:cache:dump" + rails "db:schema:cache:clear" + assert_not File.exist?("db/schema_cache.yml") + assert_not File.exist?("db/animals_schema_cache.yml") + end + end + def db_migrate_and_schema_dump_and_load(format) Dir.chdir(app_path) do generate_models_for_animals @@ -92,7 +113,7 @@ module ApplicationTests end end - def db_migrate_namespaced(namespace, expected_database) + def db_migrate_namespaced(namespace) Dir.chdir(app_path) do generate_models_for_animals output = rails("db:migrate:#{namespace}") @@ -104,7 +125,7 @@ module ApplicationTests end end - def db_migrate_status_namespaced(namespace, expected_database) + def db_migrate_status_namespaced(namespace) Dir.chdir(app_path) do generate_models_for_animals output = rails("db:migrate:status:#{namespace}") @@ -149,6 +170,7 @@ module ApplicationTests rails "generate", "model", "book", "title:string" rails "generate", "model", "dog", "name:string" write_models_for_animals + reload end test "db:create and db:drop works on all databases for env" do @@ -178,7 +200,7 @@ module ApplicationTests test "db:migrate:namespace works" do require "#{app_path}/config/environment" ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config| - db_migrate_namespaced db_config.spec_name, db_config.config["database"] + db_migrate_namespaced db_config.spec_name end end @@ -190,10 +212,20 @@ module ApplicationTests test "db:migrate:status:namespace works" do require "#{app_path}/config/environment" ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config| - db_migrate_namespaced db_config.spec_name, db_config.config["database"] - db_migrate_status_namespaced db_config.spec_name, db_config.config["database"] + db_migrate_namespaced db_config.spec_name + db_migrate_status_namespaced db_config.spec_name end end + + test "db:schema:cache:dump works on all databases" do + require "#{app_path}/config/environment" + db_migrate_and_schema_cache_dump + end + + test "db:schema:cache:clear works on all databases" do + require "#{app_path}/config/environment" + db_migrate_and_schema_cache_dump_and_schema_cache_clear + end end end end diff --git a/railties/test/application/rake/routes_test.rb b/railties/test/application/rake/routes_test.rb index 2c23ff4679..9879d1f047 100644 --- a/railties/test/application/rake/routes_test.rb +++ b/railties/test/application/rake/routes_test.rb @@ -6,6 +6,7 @@ module ApplicationTests module RakeTests class RakeRoutesTest < ActiveSupport::TestCase include ActiveSupport::Testing::Isolation + setup :build_app teardown :teardown_app @@ -17,13 +18,28 @@ module ApplicationTests RUBY assert_equal <<~MESSAGE, run_rake_routes - Prefix Verb URI Pattern Controller#Action - cart GET /cart(.:format) cart#show - rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show -rails_blob_representation GET /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show - rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show -update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update - rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create + Prefix Verb URI Pattern Controller#Action + cart GET /cart(.:format) cart#show + rails_amazon_inbound_emails POST /rails/action_mailbox/amazon/inbound_emails(.:format) action_mailbox/ingresses/amazon/inbound_emails#create + rails_mandrill_inbound_emails POST /rails/action_mailbox/mandrill/inbound_emails(.:format) action_mailbox/ingresses/mandrill/inbound_emails#create + rails_postmark_inbound_emails POST /rails/action_mailbox/postmark/inbound_emails(.:format) action_mailbox/ingresses/postmark/inbound_emails#create + rails_relay_inbound_emails POST /rails/action_mailbox/relay/inbound_emails(.:format) action_mailbox/ingresses/relay/inbound_emails#create + rails_sendgrid_inbound_emails POST /rails/action_mailbox/sendgrid/inbound_emails(.:format) action_mailbox/ingresses/sendgrid/inbound_emails#create + rails_mailgun_inbound_emails POST /rails/action_mailbox/mailgun/inbound_emails/mime(.:format) action_mailbox/ingresses/mailgun/inbound_emails#create + rails_conductor_inbound_emails GET /rails/conductor/action_mailbox/inbound_emails(.:format) rails/conductor/action_mailbox/inbound_emails#index + POST /rails/conductor/action_mailbox/inbound_emails(.:format) rails/conductor/action_mailbox/inbound_emails#create + new_rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/new(.:format) rails/conductor/action_mailbox/inbound_emails#new + edit_rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/:id/edit(.:format) rails/conductor/action_mailbox/inbound_emails#edit + rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#show + PATCH /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#update + PUT /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#update + DELETE /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#destroy + rails_conductor_inbound_email_reroute POST /rails/conductor/action_mailbox/:inbound_email_id/reroute(.:format) rails/conductor/action_mailbox/reroutes#create + rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show + rails_blob_representation GET /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show + rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show + update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update + rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create MESSAGE end diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index a0cdae898b..fe56e3d076 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -145,8 +145,8 @@ module ApplicationTests # loading a specific fixture rails "db:fixtures:load", "FIXTURES=products" - assert_equal 2, ::AppTemplate::Application::Product.count - assert_equal 0, ::AppTemplate::Application::User.count + assert_equal 2, Product.count + assert_equal 0, User.count end def test_loading_only_yml_fixtures @@ -160,7 +160,10 @@ module ApplicationTests def test_scaffold_tests_pass_by_default rails "generate", "scaffold", "user", "username:string", "password:string" - with_rails_env("test") { rails("db:migrate") } + with_rails_env("test") do + rails("db:migrate") + rails("webpacker:compile") + end output = rails("test") assert_match(/7 runs, 9 assertions, 0 failures, 0 errors/, output) @@ -189,8 +192,10 @@ module ApplicationTests rails "generate", "model", "Product" rails "generate", "model", "Cart" rails "generate", "scaffold", "LineItems", "product:references", "cart:belongs_to" - with_rails_env("test") { rails("db:migrate") } - rails("webpacker:compile") + with_rails_env("test") do + rails("db:migrate") + rails("webpacker:compile") + end output = rails("test") assert_match(/7 runs, 9 assertions, 0 failures, 0 errors/, output) diff --git a/railties/test/application/server_test.rb b/railties/test/application/server_test.rb index ab9e910aed..9df36b3444 100644 --- a/railties/test/application/server_test.rb +++ b/railties/test/application/server_test.rb @@ -18,20 +18,6 @@ module ApplicationTests teardown_app end - test "deprecate support of older `config.ru`" do - remove_file "config.ru" - app_file "config.ru", <<-RUBY - require_relative 'config/environment' - run AppTemplate::Application - RUBY - - server = Rails::Server.new(config: "#{app_path}/config.ru") - server.app - - log = File.read(Rails.application.config.paths["log"].first) - assert_match(/DEPRECATION WARNING: Using `Rails::Application` subclass to start the server is deprecated/, log) - end - test "restart rails server with custom pid file path" do skip "PTY unavailable" unless available_pty? @@ -43,8 +29,8 @@ module ApplicationTests primary, replica = PTY.open pid = nil - begin - pid = Process.spawn("#{app_path}/bin/rails server -P tmp/dummy.pid", in: replica, out: replica, err: replica) + Bundler.with_original_env do + pid = Process.spawn("bin/rails server -P tmp/dummy.pid", chdir: app_path, in: replica, out: replica, err: replica) assert_output("Listening", primary) rails("restart") diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb index 5c34b205c9..0bdd2b314d 100644 --- a/railties/test/application/test_runner_test.rb +++ b/railties/test/application/test_runner_test.rb @@ -16,7 +16,7 @@ module ApplicationTests teardown_app end - def test_run_via_backwardscompatibility + def test_run_via_backwards_compatibility require "minitest/rails_plugin" assert_nothing_raised do @@ -98,6 +98,17 @@ module ApplicationTests end end + def test_run_channels + create_test_file :channels, "foo_channel" + create_test_file :channels, "bar_channel" + + rails("test:channels").tap do |output| + assert_match "FooChannelTest", output + assert_match "BarChannelTest", output + assert_match "2 runs, 2 assertions, 0 failures", output + end + end + def test_run_controllers create_test_file :controllers, "foo_controller" create_test_file :controllers, "bar_controller" @@ -131,6 +142,18 @@ module ApplicationTests end end + def test_run_mailboxes + create_test_file :mailboxes, "foo_mailbox" + create_test_file :mailboxes, "bar_mailbox" + create_test_file :models, "foo" + + rails("test:mailboxes").tap do |output| + assert_match "FooMailboxTest", output + assert_match "BarMailboxTest", output + assert_match "2 runs, 2 assertions, 0 failures", output + end + end + def test_run_functionals create_test_file :mailers, "foo_mailer" create_test_file :controllers, "bar_controller" @@ -155,11 +178,11 @@ module ApplicationTests end def test_run_all_suites - suites = [:models, :helpers, :unit, :controllers, :mailers, :functional, :integration, :jobs] + suites = [:models, :helpers, :unit, :channels, :controllers, :mailers, :functional, :integration, :jobs, :mailboxes] suites.each { |suite| create_test_file suite, "foo_#{suite}" } run_test_command("") .tap do |output| suites.each { |suite| assert_match "Foo#{suite.to_s.camelize}Test", output } - assert_match "8 runs, 8 assertions, 0 failures", output + assert_match "10 runs, 10 assertions, 0 failures", output end end @@ -523,6 +546,8 @@ module ApplicationTests end def test_run_in_parallel_with_processes + exercise_parallelization_regardless_of_machine_core_count(with: :processes) + file_name = create_parallel_processes_test_file app_file "db/schema.rb", <<-RUBY @@ -540,11 +565,7 @@ module ApplicationTests end def test_run_in_parallel_with_threads - app_path("/test/test_helper.rb") do |file_name| - file = File.read(file_name) - file.sub!(/parallelize\(([^\)]*)\)/, "parallelize(\\1, with: :threads)") - File.write(file_name, file) - end + exercise_parallelization_regardless_of_machine_core_count(with: :threads) file_name = create_parallel_threads_test_file @@ -562,6 +583,49 @@ module ApplicationTests assert_no_match "create_table(:users)", output end + def test_run_in_parallel_with_unmarshable_exception + exercise_parallelization_regardless_of_machine_core_count(with: :processes) + + file = app_file "test/fail_test.rb", <<-RUBY + require "test_helper" + class FailTest < ActiveSupport::TestCase + class BadError < StandardError + def initialize + super + @proc = ->{ } + end + end + + test "fail" do + raise BadError + assert true + end + end + RUBY + + output = run_test_command(file) + + assert_match "DRb::DRbRemoteError: FailTest::BadError", output + assert_match "1 runs, 0 assertions, 0 failures, 1 errors", output + end + + def test_run_in_parallel_with_unknown_object + exercise_parallelization_regardless_of_machine_core_count(with: :processes) + + create_scaffold + + app_file "config/environments/test.rb", <<-RUBY + Rails.application.configure do + config.action_controller.allow_forgery_protection = true + config.action_dispatch.show_exceptions = false + end + RUBY + + output = run_test_command("-n test_should_create_user") + + assert_match "ActionController::InvalidAuthenticityToken", output + end + def test_raise_error_when_specified_file_does_not_exist error = capture(:stderr) { run_test_command("test/not_exists.rb", stderr: true) } assert_match(%r{cannot load such file.+test/not_exists\.rb}, error) @@ -678,6 +742,7 @@ module ApplicationTests def test_reset_sessions_before_rollback_on_system_tests app_file "test/system/reset_session_before_rollback_test.rb", <<-RUBY require "application_system_test_case" + require "selenium/webdriver" class ResetSessionBeforeRollbackTest < ApplicationSystemTestCase def teardown_fixtures @@ -703,6 +768,32 @@ module ApplicationTests end end + def test_reset_sessions_on_failed_system_test_screenshot + app_file "test/system/reset_sessions_on_failed_system_test_screenshot_test.rb", <<~RUBY + require "application_system_test_case" + require "selenium/webdriver" + + class ResetSessionsOnFailedSystemTestScreenshotTest < ApplicationSystemTestCase + ActionDispatch::SystemTestCase.class_eval do + def take_failed_screenshot + raise Capybara::CapybaraError + end + end + + Capybara.instance_eval do + def reset_sessions! + puts "Capybara.reset_sessions! called" + end + end + + test "dummy" do + end + end + RUBY + output = run_test_command("test/system/reset_sessions_on_failed_system_test_screenshot_test.rb") + assert_match "Capybara.reset_sessions! called", output + end + def test_system_tests_are_not_run_with_the_default_test_command app_file "test/system/dummy_test.rb", <<-RUBY require "application_system_test_case" @@ -737,6 +828,7 @@ module ApplicationTests def test_system_tests_are_run_through_rake_test_when_given_in_TEST app_file "test/system/dummy_test.rb", <<-RUBY require "application_system_test_case" + require "selenium/webdriver" class DummyTest < ApplicationSystemTestCase test "something" do @@ -903,6 +995,14 @@ module ApplicationTests RUBY end + def exercise_parallelization_regardless_of_machine_core_count(with:) + app_path("test/test_helper.rb") do |file_name| + file = File.read(file_name) + file.sub!(/parallelize\(([^\)]*)\)/, "parallelize(workers: 2, with: :#{with})") + File.write(file_name, file) + end + end + def create_env_test app_file "test/unit/env_test.rb", <<-RUBY require 'test_helper' diff --git a/railties/test/application/url_generation_test.rb b/railties/test/application/url_generation_test.rb index f22b9fda3d..6bcc0b0acb 100644 --- a/railties/test/application/url_generation_test.rb +++ b/railties/test/application/url_generation_test.rb @@ -19,6 +19,7 @@ module ApplicationTests config.session_store :cookie_store, key: "_myapp_session" config.active_support.deprecation = :log config.eager_load = false + config.hosts << proc { true } end Rails.application.initialize! diff --git a/railties/test/application/zeitwerk_integration_test.rb b/railties/test/application/zeitwerk_integration_test.rb new file mode 100644 index 0000000000..cddbf5a22d --- /dev/null +++ b/railties/test/application/zeitwerk_integration_test.rb @@ -0,0 +1,257 @@ +# frozen_string_literal: true + +require "isolation/abstract_unit" +require "active_support/dependencies/zeitwerk_integration" + +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 + + def decorated? + deps.singleton_class < deps::ZeitwerkIntegration::Decorations + end + + test "ActiveSupport::Dependencies is decorated by default" do + boot + + assert decorated? + 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 + end + + test "ActiveSupport::Dependencies is not decorated in classic mode" do + add_to_config "config.autoloader = :classic" + boot + + assert_not decorated? + assert_not Rails.autoloaders.zeitwerk_enabled? + assert_nil Rails.autoloaders.main + assert_nil Rails.autoloaders.once + assert_equal 0, Rails.autoloaders.count + 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 + + test "constantize returns the value stored in the constant" do + app_file "app/models/admin/user.rb", "class Admin::User; end" + boot + + assert_same Admin::User, deps.constantize("Admin::User") + end + + test "constantize raises if the constant is unknown" do + boot + + assert_raises(NameError) { deps.constantize("Admin") } + end + + test "safe_constantize returns the value stored in the constant" do + app_file "app/models/admin/user.rb", "class Admin::User; end" + boot + + assert_same Admin::User, deps.safe_constantize("Admin::User") + end + + test "safe_constantize returns nil for unknown constants" do + boot + + assert_nil deps.safe_constantize("Admin") + end + + test "autoloaded_constants returns autoloaded constant paths" do + app_file "app/models/admin/user.rb", "class Admin::User; end" + app_file "app/models/post.rb", "class Post; end" + boot + + assert Admin::User + assert_equal ["Admin", "Admin::User"], deps.autoloaded_constants + end + + test "autoloaded? says if a constant has been autoloaded" do + app_file "app/models/user.rb", "class User; end" + app_file "app/models/post.rb", "class Post; end" + boot + + assert Post + assert deps.autoloaded?("Post") + assert deps.autoloaded?(Post) + assert_not deps.autoloaded?("User") + end + + 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" + boot("production") + + assert $zeitwerk_integration_test_user + assert $zeitwerk_integration_test_post + end + + test "eager loading loads anything managed by Zeitwerk" do + $zeitwerk_integration_test_user = false + 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 paths that are below Gem.path go to the once autoloader" do + app_dir "extras" + add_to_config 'config.autoload_paths << "#{Rails.root}/extras"' + + # Mocks Gem.path to include the extras directory. + Gem.singleton_class.prepend( + Module.new do + def path + super + ["#{Rails.root}/extras"] + end + end + ) + boot + + assert_not_includes Rails.autoloaders.main.dirs, "#{app_path}/extras" + assert_includes Rails.autoloaders.once.dirs, "#{app_path}/extras" + 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 + super + end + + once_autoloader = Rails.autoloaders.once + def once_autoloader.reload + $zeitwerk_integration_reload_test << :once_autoloader + super + end + + ActiveSupport::Dependencies.clear + + assert_equal %i(main_autoloader), $zeitwerk_integration_reload_test + end + + test "verbose = true sets the dependencies logger if present" do + boot + + logger = Logger.new(File::NULL) + ActiveSupport::Dependencies.logger = logger + ActiveSupport::Dependencies.verbose = true + + Rails.autoloaders.each do |autoloader| + assert_same logger, autoloader.logger + end + end + + test "verbose = true sets the Rails logger as fallback" do + boot + + ActiveSupport::Dependencies.verbose = true + + Rails.autoloaders.each do |autoloader| + assert_same Rails.logger, autoloader.logger + end + end + + test "verbose = false sets loggers to nil" do + boot + + ActiveSupport::Dependencies.verbose = true + Rails.autoloaders.each do |autoloader| + assert autoloader.logger + end + + ActiveSupport::Dependencies.verbose = false + Rails.autoloaders.each do |autoloader| + assert_nil autoloader.logger + end + end + + test "unhooks" do + boot + + assert_equal Module, Module.method(:const_missing).owner + assert_equal :no_op, deps.unhook! + end + + test "autoloaders.logger=" do + boot + + logger = ->(_msg) { } + Rails.autoloaders.logger = logger + + Rails.autoloaders.each do |autoloader| + assert_same logger, autoloader.logger + end + + Rails.autoloaders.logger = Rails.logger + + Rails.autoloaders.each do |autoloader| + assert_same Rails.logger, autoloader.logger + end + + Rails.autoloaders.logger = nil + + Rails.autoloaders.each do |autoloader| + assert_nil autoloader.logger + end + end +end diff --git a/railties/test/command/base_test.rb b/railties/test/command/base_test.rb index a49ae8aae7..9132c8b4af 100644 --- a/railties/test/command/base_test.rb +++ b/railties/test/command/base_test.rb @@ -4,10 +4,12 @@ require "abstract_unit" require "rails/command" require "rails/commands/generate/generate_command" require "rails/commands/secrets/secrets_command" +require "rails/commands/db/system/change/change_command" class Rails::Command::BaseTest < ActiveSupport::TestCase test "printing commands" do assert_equal %w(generate), Rails::Command::GenerateCommand.printing_commands assert_equal %w(secrets:setup secrets:edit secrets:show), Rails::Command::SecretsCommand.printing_commands + assert_equal %w(db:system:change), Rails::Command::Db::System::ChangeCommand.printing_commands end end diff --git a/railties/test/commands/console_test.rb b/railties/test/commands/console_test.rb index 0b2fe204f8..1941c83d6d 100644 --- a/railties/test/commands/console_test.rb +++ b/railties/test/commands/console_test.rb @@ -94,28 +94,7 @@ class Rails::ConsoleTest < ActiveSupport::TestCase assert_match(/\sspecial-production\s/, output) end - def test_rails_env_is_production_when_first_argument_is_p - assert_deprecated do - start ["p"] - assert_match(/\sproduction\s/, output) - end - end - - def test_rails_env_is_test_when_first_argument_is_t - assert_deprecated do - start ["t"] - assert_match(/\stest\s/, output) - end - end - - def test_rails_env_is_development_when_argument_is_d - assert_deprecated do - start ["d"] - assert_match(/\sdevelopment\s/, output) - end - end - - def test_rails_env_is_dev_when_argument_is_dev_and_dev_env_is_present + def test_rails_env_is_dev_when_environment_option_is_dev_and_dev_env_is_present Rails::Command::ConsoleCommand.class_eval do alias_method :old_environments, :available_environments @@ -124,9 +103,7 @@ class Rails::ConsoleTest < ActiveSupport::TestCase end end - assert_deprecated do - assert_match("dev", parse_arguments(["dev"])[:environment]) - end + assert_match("dev", parse_arguments(["-e", "dev"])[:environment]) ensure Rails::Command::ConsoleCommand.class_eval do undef_method :available_environments diff --git a/railties/test/commands/credentials_test.rb b/railties/test/commands/credentials_test.rb index 7842b0db61..10d0ba1cae 100644 --- a/railties/test/commands/credentials_test.rb +++ b/railties/test/commands/credentials_test.rb @@ -63,6 +63,14 @@ class Rails::Command::CredentialsCommandTest < ActiveSupport::TestCase end end + test "edit command does not raise when an initializer tries to access non-existent credentials" do + app_file "config/initializers/raise_when_loaded.rb", <<-RUBY + Rails.application.credentials.missing_key! + RUBY + + assert_match(/access_key_id: 123/, run_edit_command(environment: "qa")) + end + test "show credentials" do assert_match(/access_key_id: 123/, run_show_command) end diff --git a/railties/test/commands/db_system_change_test.rb b/railties/test/commands/db_system_change_test.rb new file mode 100644 index 0000000000..2ff45a7878 --- /dev/null +++ b/railties/test/commands/db_system_change_test.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require "isolation/abstract_unit" +require "rails/command" +require "rails/commands/db/system/change/change_command" + +class Rails::Command::Db::System::ChangeCommandTest < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation + + setup { build_app } + + teardown { teardown_app } + + test "change to existing database" do + change_database(to: "sqlite3") + + output = change_database(to: "sqlite3") + + assert_match "identical config/database.yml", output + assert_match "gsub Gemfile", output + end + + test "change to invalid database" do + output = change_database(to: "invalid-db") + + assert_match <<~MSG.squish, output + Invalid value for --to option. + Supported preconfigurations are: + mysql, postgresql, sqlite3, oracle, frontbase, + ibm_db, sqlserver, jdbcmysql, jdbcsqlite3, + jdbcpostgresql, jdbc. + MSG + end + + test "change to postgresql" do + output = change_database(to: "postgresql") + + assert_match "force config/database.yml", output + assert_match "gsub Gemfile", output + end + + test "change to mysql" do + output = change_database(to: "mysql") + + assert_match "force config/database.yml", output + assert_match "gsub Gemfile", output + end + + test "change to sqlite3" do + change_database(to: "postgresql") + output = change_database(to: "sqlite3") + + assert_match "force config/database.yml", output + assert_match "gsub Gemfile", output + end + + private + def change_database(to:, **options) + args = ["--to", to] + rails "db:system:change", args, **options + end +end diff --git a/railties/test/commands/dbconsole_test.rb b/railties/test/commands/dbconsole_test.rb index 5e3eca6585..65f6916acb 100644 --- a/railties/test/commands/dbconsole_test.rb +++ b/railties/test/commands/dbconsole_test.rb @@ -99,28 +99,12 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase ENV["RACK_ENV"] = nil end - def test_rails_env_is_development_when_argument_is_dev - assert_deprecated do - stub_available_environments([ "development", "test" ]) do - assert_match("development", parse_arguments([ "dev" ])[:environment]) - end - end - end - def test_rails_env_is_development_when_environment_option_is_dev stub_available_environments([ "development", "test" ]) do assert_match("development", parse_arguments([ "-e", "dev" ])[:environment]) end end - def test_rails_env_is_dev_when_argument_is_dev_and_dev_env_is_present - assert_deprecated do - stub_available_environments([ "dev" ]) do - assert_match("dev", parse_arguments([ "dev" ])[:environment]) - end - end - end - def test_mysql start(adapter: "mysql2", database: "db") assert_not aborted @@ -128,9 +112,9 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase end def test_mysql_full - start(adapter: "mysql2", database: "db", host: "locahost", port: 1234, socket: "socket", username: "user", password: "qwerty", encoding: "UTF-8") + start(adapter: "mysql2", database: "db", host: "localhost", port: 1234, socket: "socket", username: "user", password: "qwerty", encoding: "UTF-8") assert_not aborted - assert_equal [%w[mysql mysql5], "--host=locahost", "--port=1234", "--socket=socket", "--user=user", "--default-character-set=UTF-8", "-p", "db"], dbconsole.find_cmd_and_exec_args + assert_equal [%w[mysql mysql5], "--host=localhost", "--port=1234", "--socket=socket", "--user=user", "--default-character-set=UTF-8", "-p", "db"], dbconsole.find_cmd_and_exec_args end def test_mysql_include_password @@ -265,14 +249,14 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase stdout = capture(:stdout) do Rails::Command.invoke(:dbconsole, ["-h"]) end - assert_match(/rails dbconsole \[environment\]/, stdout) + assert_match(/rails dbconsole \[options\]/, stdout) end def test_print_help_long stdout = capture(:stdout) do Rails::Command.invoke(:dbconsole, ["--help"]) end - assert_match(/rails dbconsole \[environment\]/, stdout) + assert_match(/rails dbconsole \[options\]/, stdout) end attr_reader :aborted, :output @@ -308,11 +292,9 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase def capture_abort @aborted = false @output = capture(:stderr) do - begin - yield - rescue SystemExit - @aborted = true - end + yield + rescue SystemExit + @aborted = true end end diff --git a/railties/test/commands/routes_test.rb b/railties/test/commands/routes_test.rb index 693e532c5b..b4f927060e 100644 --- a/railties/test/commands/routes_test.rb +++ b/railties/test/commands/routes_test.rb @@ -17,29 +17,28 @@ class Rails::Command::RoutesTest < ActiveSupport::TestCase end RUBY - expected_post_output = [" Prefix Verb URI Pattern Controller#Action", - " new_post GET /post/new(.:format) posts#new", - "edit_post GET /post/edit(.:format) posts#edit", - " post GET /post(.:format) posts#show", - " PATCH /post(.:format) posts#update", - " PUT /post(.:format) posts#update", - " DELETE /post(.:format) posts#destroy", - " POST /post(.:format) posts#create\n"].join("\n") - - output = run_routes_command(["-c", "PostController"]) - assert_equal expected_post_output, output - - expected_perm_output = [" Prefix Verb URI Pattern Controller#Action", - " new_user_permission GET /user_permission/new(.:format) user_permissions#new", - "edit_user_permission GET /user_permission/edit(.:format) user_permissions#edit", - " user_permission GET /user_permission(.:format) user_permissions#show", - " PATCH /user_permission(.:format) user_permissions#update", - " PUT /user_permission(.:format) user_permissions#update", - " DELETE /user_permission(.:format) user_permissions#destroy", - " POST /user_permission(.:format) user_permissions#create\n"].join("\n") - - output = run_routes_command(["-c", "UserPermissionController"]) - assert_equal expected_perm_output, output + assert_equal <<~OUTPUT, run_routes_command([ "-c", "PostController" ]) + Prefix Verb URI Pattern Controller#Action + new_post GET /post/new(.:format) posts#new + edit_post GET /post/edit(.:format) posts#edit + post GET /post(.:format) posts#show + PATCH /post(.:format) posts#update + PUT /post(.:format) posts#update + DELETE /post(.:format) posts#destroy + POST /post(.:format) posts#create + rails_postmark_inbound_emails POST /rails/action_mailbox/postmark/inbound_emails(.:format) action_mailbox/ingresses/postmark/inbound_emails#create + OUTPUT + + assert_equal <<~OUTPUT, run_routes_command([ "-c", "UserPermissionController" ]) + Prefix Verb URI Pattern Controller#Action + new_user_permission GET /user_permission/new(.:format) user_permissions#new + edit_user_permission GET /user_permission/edit(.:format) user_permissions#edit + user_permission GET /user_permission(.:format) user_permissions#show + PATCH /user_permission(.:format) user_permissions#update + PUT /user_permission(.:format) user_permissions#update + DELETE /user_permission(.:format) user_permissions#destroy + POST /user_permission(.:format) user_permissions#create + OUTPUT end test "rails routes with global search key" do @@ -51,25 +50,33 @@ class Rails::Command::RoutesTest < ActiveSupport::TestCase end RUBY - output = run_routes_command(["-g", "show"]) - assert_equal <<~MESSAGE, output - Prefix Verb URI Pattern Controller#Action - cart GET /cart(.:format) cart#show - rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show - rails_blob_representation GET /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show - rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show + assert_equal <<~MESSAGE, run_routes_command([ "-g", "show" ]) + Prefix Verb URI Pattern Controller#Action + cart GET /cart(.:format) cart#show + rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#show + rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show + rails_blob_representation GET /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show + rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show MESSAGE - output = run_routes_command(["-g", "POST"]) - assert_equal <<~MESSAGE, output - Prefix Verb URI Pattern Controller#Action - POST /cart(.:format) cart#create - rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create + assert_equal <<~MESSAGE, run_routes_command([ "-g", "POST" ]) + Prefix Verb URI Pattern Controller#Action + POST /cart(.:format) cart#create + rails_amazon_inbound_emails POST /rails/action_mailbox/amazon/inbound_emails(.:format) action_mailbox/ingresses/amazon/inbound_emails#create + rails_mandrill_inbound_emails POST /rails/action_mailbox/mandrill/inbound_emails(.:format) action_mailbox/ingresses/mandrill/inbound_emails#create + rails_postmark_inbound_emails POST /rails/action_mailbox/postmark/inbound_emails(.:format) action_mailbox/ingresses/postmark/inbound_emails#create + rails_relay_inbound_emails POST /rails/action_mailbox/relay/inbound_emails(.:format) action_mailbox/ingresses/relay/inbound_emails#create + rails_sendgrid_inbound_emails POST /rails/action_mailbox/sendgrid/inbound_emails(.:format) action_mailbox/ingresses/sendgrid/inbound_emails#create + rails_mailgun_inbound_emails POST /rails/action_mailbox/mailgun/inbound_emails/mime(.:format) action_mailbox/ingresses/mailgun/inbound_emails#create + POST /rails/conductor/action_mailbox/inbound_emails(.:format) rails/conductor/action_mailbox/inbound_emails#create + rails_conductor_inbound_email_reroute POST /rails/conductor/action_mailbox/:inbound_email_id/reroute(.:format) rails/conductor/action_mailbox/reroutes#create + rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create MESSAGE - output = run_routes_command(["-g", "basketballs"]) - assert_equal " Prefix Verb URI Pattern Controller#Action\n" \ - "basketballs GET /basketballs(.:format) basketball#index\n", output + assert_equal <<~MESSAGE, run_routes_command([ "-g", "basketballs" ]) + Prefix Verb URI Pattern Controller#Action + basketballs GET /basketballs(.:format) basketball#index + MESSAGE end test "rails routes with controller search key" do @@ -113,35 +120,42 @@ class Rails::Command::RoutesTest < ActiveSupport::TestCase end RUBY - expected_post_output = [" Prefix Verb URI Pattern Controller#Action", - " new_admin_post GET /admin/post/new(.:format) admin/posts#new", - "edit_admin_post GET /admin/post/edit(.:format) admin/posts#edit", - " admin_post GET /admin/post(.:format) admin/posts#show", - " PATCH /admin/post(.:format) admin/posts#update", - " PUT /admin/post(.:format) admin/posts#update", - " DELETE /admin/post(.:format) admin/posts#destroy", - " POST /admin/post(.:format) admin/posts#create\n"].join("\n") - - output = run_routes_command(["-c", "Admin::PostController"]) - assert_equal expected_post_output, output - - output = run_routes_command(["-c", "PostController"]) - assert_equal expected_post_output, output - - expected_perm_output = [" Prefix Verb URI Pattern Controller#Action", - " new_admin_user_permission GET /admin/user_permission/new(.:format) admin/user_permissions#new", - "edit_admin_user_permission GET /admin/user_permission/edit(.:format) admin/user_permissions#edit", - " admin_user_permission GET /admin/user_permission(.:format) admin/user_permissions#show", - " PATCH /admin/user_permission(.:format) admin/user_permissions#update", - " PUT /admin/user_permission(.:format) admin/user_permissions#update", - " DELETE /admin/user_permission(.:format) admin/user_permissions#destroy", - " POST /admin/user_permission(.:format) admin/user_permissions#create\n"].join("\n") - - output = run_routes_command(["-c", "Admin::UserPermissionController"]) - assert_equal expected_perm_output, output - - output = run_routes_command(["-c", "UserPermissionController"]) - assert_equal expected_perm_output, output + assert_equal <<~OUTPUT, run_routes_command([ "-c", "Admin::PostController" ]) + Prefix Verb URI Pattern Controller#Action + new_admin_post GET /admin/post/new(.:format) admin/posts#new + edit_admin_post GET /admin/post/edit(.:format) admin/posts#edit + admin_post GET /admin/post(.:format) admin/posts#show + PATCH /admin/post(.:format) admin/posts#update + PUT /admin/post(.:format) admin/posts#update + DELETE /admin/post(.:format) admin/posts#destroy + POST /admin/post(.:format) admin/posts#create + OUTPUT + + assert_equal <<~OUTPUT, run_routes_command([ "-c", "PostController" ]) + Prefix Verb URI Pattern Controller#Action + new_admin_post GET /admin/post/new(.:format) admin/posts#new + edit_admin_post GET /admin/post/edit(.:format) admin/posts#edit + admin_post GET /admin/post(.:format) admin/posts#show + PATCH /admin/post(.:format) admin/posts#update + PUT /admin/post(.:format) admin/posts#update + DELETE /admin/post(.:format) admin/posts#destroy + POST /admin/post(.:format) admin/posts#create + rails_postmark_inbound_emails POST /rails/action_mailbox/postmark/inbound_emails(.:format) action_mailbox/ingresses/postmark/inbound_emails#create + OUTPUT + + expected_permission_output = <<~OUTPUT + Prefix Verb URI Pattern Controller#Action + new_admin_user_permission GET /admin/user_permission/new(.:format) admin/user_permissions#new + edit_admin_user_permission GET /admin/user_permission/edit(.:format) admin/user_permissions#edit + admin_user_permission GET /admin/user_permission(.:format) admin/user_permissions#show + PATCH /admin/user_permission(.:format) admin/user_permissions#update + PUT /admin/user_permission(.:format) admin/user_permissions#update + DELETE /admin/user_permission(.:format) admin/user_permissions#destroy + POST /admin/user_permission(.:format) admin/user_permissions#create + OUTPUT + + assert_equal expected_permission_output, run_routes_command([ "-c", "Admin::UserPermissionController" ]) + assert_equal expected_permission_output, run_routes_command([ "-c", "UserPermissionController" ]) end test "rails routes displays message when no routes are defined" do @@ -151,63 +165,151 @@ class Rails::Command::RoutesTest < ActiveSupport::TestCase RUBY assert_equal <<~MESSAGE, run_routes_command - Prefix Verb URI Pattern Controller#Action - rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show - rails_blob_representation GET /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show - rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show - update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update - rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create + Prefix Verb URI Pattern Controller#Action + rails_amazon_inbound_emails POST /rails/action_mailbox/amazon/inbound_emails(.:format) action_mailbox/ingresses/amazon/inbound_emails#create + rails_mandrill_inbound_emails POST /rails/action_mailbox/mandrill/inbound_emails(.:format) action_mailbox/ingresses/mandrill/inbound_emails#create + rails_postmark_inbound_emails POST /rails/action_mailbox/postmark/inbound_emails(.:format) action_mailbox/ingresses/postmark/inbound_emails#create + rails_relay_inbound_emails POST /rails/action_mailbox/relay/inbound_emails(.:format) action_mailbox/ingresses/relay/inbound_emails#create + rails_sendgrid_inbound_emails POST /rails/action_mailbox/sendgrid/inbound_emails(.:format) action_mailbox/ingresses/sendgrid/inbound_emails#create + rails_mailgun_inbound_emails POST /rails/action_mailbox/mailgun/inbound_emails/mime(.:format) action_mailbox/ingresses/mailgun/inbound_emails#create + rails_conductor_inbound_emails GET /rails/conductor/action_mailbox/inbound_emails(.:format) rails/conductor/action_mailbox/inbound_emails#index + POST /rails/conductor/action_mailbox/inbound_emails(.:format) rails/conductor/action_mailbox/inbound_emails#create + new_rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/new(.:format) rails/conductor/action_mailbox/inbound_emails#new + edit_rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/:id/edit(.:format) rails/conductor/action_mailbox/inbound_emails#edit + rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#show + PATCH /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#update + PUT /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#update + DELETE /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#destroy + rails_conductor_inbound_email_reroute POST /rails/conductor/action_mailbox/:inbound_email_id/reroute(.:format) rails/conductor/action_mailbox/reroutes#create + rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show + rails_blob_representation GET /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show + rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show + update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update + rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create MESSAGE end test "rails routes with expanded option" do - begin - previous_console_winsize = IO.console.winsize - IO.console.winsize = [0, 27] + previous_console_winsize = IO.console.winsize + IO.console.winsize = [0, 27] - app_file "config/routes.rb", <<-RUBY - Rails.application.routes.draw do - get '/cart', to: 'cart#show' - end - RUBY - - output = run_routes_command(["--expanded"]) - - assert_equal <<~MESSAGE, output - --[ Route 1 ]-------------- - Prefix | cart - Verb | GET - URI | /cart(.:format) - Controller#Action | cart#show - --[ Route 2 ]-------------- - Prefix | rails_service_blob - Verb | GET - URI | /rails/active_storage/blobs/:signed_id/*filename(.:format) - Controller#Action | active_storage/blobs#show - --[ Route 3 ]-------------- - Prefix | rails_blob_representation - Verb | GET - URI | /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) - Controller#Action | active_storage/representations#show - --[ Route 4 ]-------------- - Prefix | rails_disk_service - Verb | GET - URI | /rails/active_storage/disk/:encoded_key/*filename(.:format) - Controller#Action | active_storage/disk#show - --[ Route 5 ]-------------- - Prefix | update_rails_disk_service - Verb | PUT - URI | /rails/active_storage/disk/:encoded_token(.:format) - Controller#Action | active_storage/disk#update - --[ Route 6 ]-------------- - Prefix | rails_direct_uploads - Verb | POST - URI | /rails/active_storage/direct_uploads(.:format) - Controller#Action | active_storage/direct_uploads#create - MESSAGE - ensure - IO.console.winsize = previous_console_winsize - end + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + get '/cart', to: 'cart#show' + end + RUBY + + # rubocop:disable Layout/TrailingWhitespace + assert_equal <<~MESSAGE, run_routes_command([ "--expanded" ]) + --[ Route 1 ]-------------- + Prefix | cart + Verb | GET + URI | /cart(.:format) + Controller#Action | cart#show + --[ Route 2 ]-------------- + Prefix | rails_amazon_inbound_emails + Verb | POST + URI | /rails/action_mailbox/amazon/inbound_emails(.:format) + Controller#Action | action_mailbox/ingresses/amazon/inbound_emails#create + --[ Route 3 ]-------------- + Prefix | rails_mandrill_inbound_emails + Verb | POST + URI | /rails/action_mailbox/mandrill/inbound_emails(.:format) + Controller#Action | action_mailbox/ingresses/mandrill/inbound_emails#create + --[ Route 4 ]-------------- + Prefix | rails_postmark_inbound_emails + Verb | POST + URI | /rails/action_mailbox/postmark/inbound_emails(.:format) + Controller#Action | action_mailbox/ingresses/postmark/inbound_emails#create + --[ Route 5 ]-------------- + Prefix | rails_relay_inbound_emails + Verb | POST + URI | /rails/action_mailbox/relay/inbound_emails(.:format) + Controller#Action | action_mailbox/ingresses/relay/inbound_emails#create + --[ Route 6 ]-------------- + Prefix | rails_sendgrid_inbound_emails + Verb | POST + URI | /rails/action_mailbox/sendgrid/inbound_emails(.:format) + Controller#Action | action_mailbox/ingresses/sendgrid/inbound_emails#create + --[ Route 7 ]-------------- + Prefix | rails_mailgun_inbound_emails + Verb | POST + URI | /rails/action_mailbox/mailgun/inbound_emails/mime(.:format) + Controller#Action | action_mailbox/ingresses/mailgun/inbound_emails#create + --[ Route 8 ]-------------- + Prefix | rails_conductor_inbound_emails + Verb | GET + URI | /rails/conductor/action_mailbox/inbound_emails(.:format) + Controller#Action | rails/conductor/action_mailbox/inbound_emails#index + --[ Route 9 ]-------------- + Prefix | + Verb | POST + URI | /rails/conductor/action_mailbox/inbound_emails(.:format) + Controller#Action | rails/conductor/action_mailbox/inbound_emails#create + --[ Route 10 ]------------- + Prefix | new_rails_conductor_inbound_email + Verb | GET + URI | /rails/conductor/action_mailbox/inbound_emails/new(.:format) + Controller#Action | rails/conductor/action_mailbox/inbound_emails#new + --[ Route 11 ]------------- + Prefix | edit_rails_conductor_inbound_email + Verb | GET + URI | /rails/conductor/action_mailbox/inbound_emails/:id/edit(.:format) + Controller#Action | rails/conductor/action_mailbox/inbound_emails#edit + --[ Route 12 ]------------- + Prefix | rails_conductor_inbound_email + Verb | GET + URI | /rails/conductor/action_mailbox/inbound_emails/:id(.:format) + Controller#Action | rails/conductor/action_mailbox/inbound_emails#show + --[ Route 13 ]------------- + Prefix | + Verb | PATCH + URI | /rails/conductor/action_mailbox/inbound_emails/:id(.:format) + Controller#Action | rails/conductor/action_mailbox/inbound_emails#update + --[ Route 14 ]------------- + Prefix | + Verb | PUT + URI | /rails/conductor/action_mailbox/inbound_emails/:id(.:format) + Controller#Action | rails/conductor/action_mailbox/inbound_emails#update + --[ Route 15 ]------------- + Prefix | + Verb | DELETE + URI | /rails/conductor/action_mailbox/inbound_emails/:id(.:format) + Controller#Action | rails/conductor/action_mailbox/inbound_emails#destroy + --[ Route 16 ]------------- + Prefix | rails_conductor_inbound_email_reroute + Verb | POST + URI | /rails/conductor/action_mailbox/:inbound_email_id/reroute(.:format) + Controller#Action | rails/conductor/action_mailbox/reroutes#create + --[ Route 17 ]------------- + Prefix | rails_service_blob + Verb | GET + URI | /rails/active_storage/blobs/:signed_id/*filename(.:format) + Controller#Action | active_storage/blobs#show + --[ Route 18 ]------------- + Prefix | rails_blob_representation + Verb | GET + URI | /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) + Controller#Action | active_storage/representations#show + --[ Route 19 ]------------- + Prefix | rails_disk_service + Verb | GET + URI | /rails/active_storage/disk/:encoded_key/*filename(.:format) + Controller#Action | active_storage/disk#show + --[ Route 20 ]------------- + Prefix | update_rails_disk_service + Verb | PUT + URI | /rails/active_storage/disk/:encoded_token(.:format) + Controller#Action | active_storage/disk#update + --[ Route 21 ]------------- + Prefix | rails_direct_uploads + Verb | POST + URI | /rails/active_storage/direct_uploads(.:format) + Controller#Action | active_storage/direct_uploads#create + MESSAGE + # rubocop:enable Layout/TrailingWhitespace + ensure + IO.console.winsize = previous_console_winsize end private diff --git a/railties/test/commands/server_test.rb b/railties/test/commands/server_test.rb index e5b1da6ea4..25b89ecbd8 100644 --- a/railties/test/commands/server_test.rb +++ b/railties/test/commands/server_test.rb @@ -32,6 +32,12 @@ class Rails::Command::ServerCommandTest < ActiveSupport::TestCase assert_match(/Could not find server "tin". Maybe you meant "thin"?/, run_command("--using", "tin")) end + def test_using_server_mistype_without_suggestion + output = run_command("--using", "t") + assert_match(/Could not find server "t"/, output) + assert_no_match(/Maybe you meant/, output) + end + def test_using_positional_argument_deprecation assert_match(/DEPRECATION WARNING/, run_command("tin")) end @@ -225,10 +231,10 @@ class Rails::Command::ServerCommandTest < ActiveSupport::TestCase end def test_records_user_supplied_options - server_options = parse_arguments(["-p", 3001]) + server_options = parse_arguments(["-p", "3001"]) assert_equal [:Port], server_options[:user_supplied_options] - server_options = parse_arguments(["--port", 3001]) + server_options = parse_arguments(["--port", "3001"]) assert_equal [:Port], server_options[:user_supplied_options] server_options = parse_arguments(["-p3001", "-C", "--binding", "127.0.0.1"]) diff --git a/railties/test/credentials_test.rb b/railties/test/credentials_test.rb deleted file mode 100644 index 03370e0fc7..0000000000 --- a/railties/test/credentials_test.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -require "isolation/abstract_unit" - -class Rails::CredentialsTest < ActiveSupport::TestCase - include ActiveSupport::Testing::Isolation - - setup :build_app - teardown :teardown_app - - test "reads credentials from environment specific path" do - with_credentials do |content, key| - Dir.chdir(app_path) do - Dir.mkdir("config/credentials") - File.write("config/credentials/production.yml.enc", content) - File.write("config/credentials/production.key", key) - end - - app("production") - - assert_equal "revealed", Rails.application.credentials.mystery - end - end - - test "reads credentials from customized path and key" do - with_credentials do |content, key| - Dir.chdir(app_path) do - Dir.mkdir("config/credentials") - File.write("config/credentials/staging.yml.enc", content) - File.write("config/credentials/staging.key", key) - end - - add_to_env_config("production", "config.credentials.content_path = config.root.join('config/credentials/staging.yml.enc')") - add_to_env_config("production", "config.credentials.key_path = config.root.join('config/credentials/staging.key')") - app("production") - - assert_equal "revealed", Rails.application.credentials.mystery - end - end - - private - def with_credentials - key = "2117e775dc2024d4f49ddf3aeb585919" - # secret_key_base: secret - # mystery: revealed - content = "vgvKu4MBepIgZ5VHQMMPwnQNsLlWD9LKmJHu3UA/8yj6x+3fNhz3DwL9brX7UA==--qLdxHP6e34xeTAiI--nrcAsleXuo9NqiEuhntAhw==" - yield(content, key) - end -end diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb index 6d53230eab..44d4e92256 100644 --- a/railties/test/generators/actions_test.rb +++ b/railties/test/generators/actions_test.rb @@ -303,12 +303,30 @@ class ActionsTest < Rails::Generators::TestCase end def test_generate_should_run_script_generate_with_argument_and_options - assert_called_with(generator, :run_ruby_script, ["bin/rails generate model MyModel", verbose: false]) do - action :generate, "model", "MyModel" + run_generator + action :generate, "model", "MyModel" + assert_file "app/models/my_model.rb", /MyModel/ + end + + def test_generate_aborts_when_subprocess_fails_if_requested + run_generator + content = capture(:stderr) do + assert_raises SystemExit do + action :generate, "model", "MyModel:ADsad", abort_on_failure: true + action :generate, "model", "MyModel" + end end + assert_match(/wrong constant name MyModel:aDsad/, content) + assert_no_file "app/models/my_model.rb" end - def test_rails_should_run_rake_command_with_default_env + def test_generate_should_run_command_without_env + assert_called_with(generator, :run, ["rails generate model MyModel name:string", verbose: false]) do + action :generate, "model", "MyModel", "name:string" + end + end + + def test_rake_should_run_rake_command_with_default_env assert_called_with(generator, :run, ["rake log:clear RAILS_ENV=development", verbose: false]) do with_rails_env nil do action :rake, "log:clear" @@ -316,13 +334,13 @@ class ActionsTest < Rails::Generators::TestCase end end - def test_rails_with_env_option_should_run_rake_command_in_env + def test_rake_with_env_option_should_run_rake_command_in_env assert_called_with(generator, :run, ["rake log:clear RAILS_ENV=production", verbose: false]) do action :rake, "log:clear", env: "production" end end - test "rails command with RAILS_ENV variable should run rake command in env" do + test "rake with RAILS_ENV variable should run rake command in env" do assert_called_with(generator, :run, ["rake log:clear RAILS_ENV=production", verbose: false]) do with_rails_env "production" do action :rake, "log:clear" @@ -338,7 +356,7 @@ class ActionsTest < Rails::Generators::TestCase end end - test "rails command with sudo option should run rake command with sudo" do + test "rake with sudo option should run rake command with sudo" do assert_called_with(generator, :run, ["sudo rake log:clear RAILS_ENV=development", verbose: false]) do with_rails_env nil do action :rake, "log:clear", sudo: true @@ -400,15 +418,6 @@ class ActionsTest < Rails::Generators::TestCase end end - def test_capify_should_run_the_capify_command - content = capture(:stderr) do - assert_called_with(generator, :run, ["capify .", verbose: false]) do - action :capify! - end - end - assert_match(/DEPRECATION WARNING: `capify!` is deprecated/, content) - end - def test_route_should_add_data_to_the_routes_block_in_config_routes run_generator route_command = "route '/login', controller: 'sessions', action: 'new'" diff --git a/railties/test/generators/api_app_generator_test.rb b/railties/test/generators/api_app_generator_test.rb index 4f2894e71e..4b9878187b 100644 --- a/railties/test/generators/api_app_generator_test.rb +++ b/railties/test/generators/api_app_generator_test.rb @@ -14,9 +14,9 @@ class ApiAppGeneratorTest < Rails::Generators::TestCase super Kernel.silence_warnings do - Thor::Base.shell.send(:attr_accessor, :always_force) + Thor::Base.shell.attr_accessor :always_force @shell = Thor::Base.shell.new - @shell.send(:always_force=, true) + @shell.always_force = true end end diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index f5356a358f..1ee9e43e89 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -81,6 +81,7 @@ DEFAULT_APP_FILES = %w( test/test_helper.rb test/fixtures test/fixtures/files + test/channels/application_cable/connection_test.rb test/controllers test/models test/helpers @@ -198,7 +199,7 @@ class AppGeneratorTest < Rails::Generators::TestCase end end - def test_new_application_use_json_serialzier + def test_new_application_use_json_serializer run_generator assert_file("config/initializers/cookies_serializer.rb", /Rails\.application\.config\.action_dispatch\.cookies_serializer = :json/) @@ -230,6 +231,14 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_equal "false\n", output end + def test_csp_initializer_include_connect_src_example + run_generator + + assert_file "config/initializers/content_security_policy.rb" do |content| + assert_match(/# policy\.connect_src/, content) + end + end + def test_app_update_keep_the_cookie_serializer_if_it_is_already_configured app_root = File.join(destination_root, "myapp") run_generator [app_root] @@ -300,10 +309,10 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_app_update_does_not_generate_yarn_contents_when_bin_yarn_is_not_used app_root = File.join(destination_root, "myapp") - run_generator [app_root, "--skip-yarn"] + run_generator [app_root, "--skip-javascript"] stub_rails_application(app_root) do - generator = Rails::Generators::AppGenerator.new ["rails"], { update: true, skip_yarn: true }, { destination_root: app_root, shell: @shell } + generator = Rails::Generators::AppGenerator.new ["rails"], { update: true, skip_javascript: true }, { destination_root: app_root, shell: @shell } generator.send(:app_const) quietly { generator.send(:update_bin_files) } @@ -355,6 +364,8 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "#{app_root}/config/environments/production.rb" do |content| assert_no_match(/config\.action_cable/, content) end + + assert_no_file "#{app_root}/test/channels/application_cable/connection_test.rb" end def test_app_update_does_not_generate_bootsnap_contents_when_skip_bootsnap_is_given @@ -427,6 +438,36 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_no_file "#{app_root}/config/storage.yml" end + def test_generator_skips_action_mailbox_when_skip_action_mailbox_is_given + run_generator [destination_root, "--skip-action-mailbox"] + assert_file "#{application_path}/config/application.rb", /#\s+require\s+["']action_mailbox\/engine["']/ + end + + def test_generator_skips_action_mailbox_when_skip_active_record_is_given + run_generator [destination_root, "--skip-active-record"] + assert_file "#{application_path}/config/application.rb", /#\s+require\s+["']action_mailbox\/engine["']/ + end + + def test_generator_skips_action_mailbox_when_skip_active_storage_is_given + run_generator [destination_root, "--skip-active-storage"] + assert_file "#{application_path}/config/application.rb", /#\s+require\s+["']action_mailbox\/engine["']/ + end + + def test_generator_skips_action_text_when_skip_action_text_is_given + run_generator [destination_root, "--skip-action-text"] + assert_file "#{application_path}/config/application.rb", /#\s+require\s+["']action_text\/engine["']/ + end + + def test_generator_skips_action_text_when_skip_active_record_is_given + run_generator [destination_root, "--skip-active-record"] + assert_file "#{application_path}/config/application.rb", /#\s+require\s+["']action_text\/engine["']/ + end + + def test_generator_skips_action_text_when_skip_active_storage_is_given + run_generator [destination_root, "--skip-active-storage"] + assert_file "#{application_path}/config/application.rb", /#\s+require\s+["']action_text\/engine["']/ + end + def test_app_update_does_not_change_config_target_version run_generator @@ -485,7 +526,7 @@ class AppGeneratorTest < Rails::Generators::TestCase if defined?(JRUBY_VERSION) assert_gem "activerecord-jdbcsqlite3-adapter" else - assert_gem "sqlite3" + assert_gem "sqlite3", "'~> 1.3', '>= 1.3.6'" end end @@ -735,6 +776,24 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_bundler_command_called("install") end + def test_generation_use_original_bundle_environment + generator([destination_root], skip_webpack_install: true) + + mock_original_env = -> do + { "BUNDLE_RUBYONRAILS__ORG" => "user:pass" } + end + + ensure_environment_is_set = -> *_args do + assert_equal "user:pass", ENV["BUNDLE_RUBYONRAILS__ORG"] + end + + Bundler.stub :original_env, mock_original_env do + generator.stub :exec_bundle_command, ensure_environment_is_set do + quietly { generator.invoke_all } + end + end + end + def test_dev_option generator([destination_root], dev: true, skip_webpack_install: true) @@ -807,6 +866,9 @@ class AppGeneratorTest < Rails::Generators::TestCase end assert_no_gem "webpacker" + assert_file "config/initializers/content_security_policy.rb" do |content| + assert_no_match(/policy\.connect_src/, content) + end end def test_webpack_option_with_js_framework @@ -1048,7 +1110,7 @@ class AppGeneratorTest < Rails::Generators::TestCase end def assert_bundler_command_called(target_command) - command_check = -> command do + command_check = -> (command, env = {}) do @command_called ||= 0 case command diff --git a/railties/test/generators/channel_generator_test.rb b/railties/test/generators/channel_generator_test.rb index 1cb8465539..1a25422c3c 100644 --- a/railties/test/generators/channel_generator_test.rb +++ b/railties/test/generators/channel_generator_test.rb @@ -67,12 +67,23 @@ class ChannelGeneratorTest < Rails::Generators::TestCase assert_file "app/javascript/channels/consumer.js" end + def test_invokes_default_test_framework + run_generator %w(chat -t=test_unit) + + assert_file "test/channels/chat_channel_test.rb" do |test| + assert_match(/class ChatChannelTest < ActionCable::Channel::TestCase/, test) + assert_match(/# test "subscribes" do/, test) + assert_match(/# assert subscription.confirmed\?/, test) + end + end + def test_channel_on_revoke run_generator ["chat"] run_generator ["chat"], behavior: :revoke assert_no_file "app/channels/chat_channel.rb" assert_no_file "app/javascript/channels/chat_channel.js" + assert_no_file "test/channels/chat_channel_test.rb" assert_file "app/channels/application_cable/channel.rb" assert_file "app/channels/application_cable/connection.rb" @@ -88,5 +99,8 @@ class ChannelGeneratorTest < Rails::Generators::TestCase assert_no_file "app/javascript/channels/chat_channel_channel.js" assert_file "app/javascript/channels/chat_channel.js" + + assert_no_file "test/channels/chat_channel_channel_test.rb" + assert_file "test/channels/chat_channel_test.rb" end end diff --git a/railties/test/generators/db_system_change_generator_test.rb b/railties/test/generators/db_system_change_generator_test.rb new file mode 100644 index 0000000000..d476bfd2dc --- /dev/null +++ b/railties/test/generators/db_system_change_generator_test.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require "generators/generators_test_helper" +require "rails/generators/rails/db/system/change/change_generator" + +module Rails + module Generators + module Db + module System + class ChangeGeneratorTest < Rails::Generators::TestCase + include GeneratorsTestHelper + + setup do + copy_gemfile( + GemfileEntry.new("sqlite3", nil, "Use sqlite3 as the database for Active Record") + ) + end + + test "change to invalid database" do + output = capture(:stderr) do + run_generator ["--to", "invalid-db"] + end + + assert_match <<~MSG.squish, output + Invalid value for --to option. + Supported preconfigurations are: + mysql, postgresql, sqlite3, oracle, frontbase, + ibm_db, sqlserver, jdbcmysql, jdbcsqlite3, + jdbcpostgresql, jdbc. + MSG + end + + test "change to postgresql" do + run_generator ["--to", "postgresql"] + + assert_file("config/database.yml") do |content| + assert_match "adapter: postgresql", content + assert_match "database: test_app", content + end + + assert_file("Gemfile") do |content| + assert_match "# Use pg as the database for Active Record", content + assert_match "gem 'pg'", content + end + end + + test "change to mysql" do + run_generator ["--to", "mysql"] + + assert_file("config/database.yml") do |content| + assert_match "adapter: mysql2", content + assert_match "database: test_app", content + end + + assert_file("Gemfile") do |content| + assert_match "# Use mysql2 as the database for Active Record", content + assert_match "gem 'mysql2'", content + end + end + + test "change to sqlite3" do + run_generator ["--to", "sqlite3"] + + assert_file("config/database.yml") do |content| + assert_match "adapter: sqlite3", content + assert_match "db/development.sqlite3", content + end + + assert_file("Gemfile") do |content| + assert_match "# Use sqlite3 as the database for Active Record", content + assert_match "gem 'sqlite3'", content + end + end + end + end + end + end +end diff --git a/railties/test/generators/generators_test_helper.rb b/railties/test/generators/generators_test_helper.rb index 25d5dba1d8..8b42cb83db 100644 --- a/railties/test/generators/generators_test_helper.rb +++ b/railties/test/generators/generators_test_helper.rb @@ -30,6 +30,12 @@ module GeneratorsTestHelper include ActiveSupport::Testing::Stream include ActiveSupport::Testing::MethodCallAssertions + GemfileEntry = Struct.new(:name, :version, :comment, :options, :commented_out) do + def initialize(name, version, comment, options = {}, commented_out = false) + super + end + end + def self.included(base) base.class_eval do destination File.join(Rails.root, "tmp") @@ -63,4 +69,38 @@ module GeneratorsTestHelper FileUtils.mkdir_p(destination) FileUtils.cp routes, File.join(destination, "routes.rb") end + + def copy_gemfile(*gemfile_entries) + locals = gemfile_locals.merge(gemfile_entries: gemfile_entries) + gemfile = File.expand_path("../../lib/rails/generators/rails/app/templates/Gemfile.tt", __dir__) + gemfile = evaluate_template(gemfile, locals) + destination = File.join(destination_root) + File.write File.join(destination, "Gemfile"), gemfile + end + + def evaluate_template(file, locals = {}) + erb = if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+ + ERB.new(File.read(file), trim_mode: "-", eoutvar: "@output_buffer") + else + ERB.new(File.read(file), nil, "-", "@output_buffer") + end + context = Class.new do + locals.each do |local, value| + class_attribute local, default: value + end + end + erb.result(context.new.instance_eval("binding")) + end + + private + def gemfile_locals + { + skip_active_storage: true, + depend_on_bootsnap: false, + depend_on_listen: false, + spring_install: false, + depends_on_system_test: false, + options: ActiveSupport::OrderedOptions.new, + } + end end diff --git a/railties/test/generators/helper_generator_test.rb b/railties/test/generators/helper_generator_test.rb index 4cdb6adf82..192839799e 100644 --- a/railties/test/generators/helper_generator_test.rb +++ b/railties/test/generators/helper_generator_test.rb @@ -30,12 +30,17 @@ class HelperGeneratorTest < Rails::Generators::TestCase require "#{destination_root}/app/helpers/products_helper" assert_nothing_raised do - begin - run_generator ["admin::products"] - ensure - # cleanup - Object.send(:remove_const, :ProductsHelper) - end + run_generator ["admin::products"] + ensure + # cleanup + Object.send(:remove_const, :ProductsHelper) end end + + def test_helper_suffix_is_not_duplicated + run_generator %w(products_helper) + + assert_no_file "app/helpers/products_helper_helper.rb" + assert_file "app/helpers/products_helper.rb" + end end diff --git a/railties/test/generators/integration_test_generator_test.rb b/railties/test/generators/integration_test_generator_test.rb index 82791f1a27..2ec4895096 100644 --- a/railties/test/generators/integration_test_generator_test.rb +++ b/railties/test/generators/integration_test_generator_test.rb @@ -15,4 +15,11 @@ class IntegrationTestGeneratorTest < Rails::Generators::TestCase run_generator %w(iguchi/integration) assert_file "test/integration/iguchi/integration_test.rb", /class Iguchi::IntegrationTest < ActionDispatch::IntegrationTest/ end + + def test_test_suffix_is_not_duplicated + run_generator %w(integration_test) + + assert_no_file "test/integration/integration_test_test.rb" + assert_file "test/integration/integration_test.rb" + end end diff --git a/railties/test/generators/mailer_generator_test.rb b/railties/test/generators/mailer_generator_test.rb index ddac6e1a1e..099e06c4d3 100644 --- a/railties/test/generators/mailer_generator_test.rb +++ b/railties/test/generators/mailer_generator_test.rb @@ -119,7 +119,7 @@ class MailerGeneratorTest < Rails::Generators::TestCase assert_match(/haml \[not found\]/, content) end - def test_mailer_with_namedspaced_mailer + def test_mailer_with_namespaced_mailer run_generator ["Farm::Animal", "moos"] assert_file "app/mailers/farm/animal_mailer.rb" do |mailer| assert_match(/class Farm::AnimalMailer < ApplicationMailer/, mailer) diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb index b06db6dd8a..134659f285 100644 --- a/railties/test/generators/model_generator_test.rb +++ b/railties/test/generators/model_generator_test.rb @@ -104,7 +104,7 @@ class ModelGeneratorTest < Rails::Generators::TestCase ActiveRecord::Base.pluralize_table_names = true end - def test_migration_with_namespaces_in_model_name_without_plurization + def test_migration_with_namespaces_in_model_name_without_pluralization ActiveRecord::Base.pluralize_table_names = false run_generator ["Gallery::Image"] assert_migration "db/migrate/create_gallery_image", /class CreateGalleryImage < ActiveRecord::Migration\[[0-9.]+\]/ diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb index 66286fc554..f45464f8d0 100644 --- a/railties/test/generators/plugin_generator_test.rb +++ b/railties/test/generators/plugin_generator_test.rb @@ -442,7 +442,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase end end - def test_dummy_appplication_skip_listen_by_default + def test_dummy_application_skip_listen_by_default run_generator assert_file "test/dummy/config/environments/development.rb" do |contents| @@ -712,38 +712,6 @@ class PluginGeneratorTest < Rails::Generators::TestCase Object.send(:remove_const, "ENGINE_ROOT") end - def test_after_bundle_callback - path = "http://example.org/rails_template" - template = +%{ after_bundle { run "echo ran after_bundle" } } - template.instance_eval "def read; self; end" # Make the string respond to read - - check_open = -> *args do - assert_equal [ path, "Accept" => "application/x-thor-template" ], args - template - end - - sequence = ["echo ran after_bundle"] - @sequence_step ||= 0 - ensure_bundler_first = -> command do - assert_equal sequence[@sequence_step], command, "commands should be called in sequence #{sequence}" - @sequence_step += 1 - end - - content = nil - generator([destination_root], template: path).stub(:open, check_open, template) do - generator.stub(:bundle_command, ensure_bundler_first) do - generator.stub(:run, ensure_bundler_first) do - silence_stream($stdout) do - content = capture(:stderr) { generator.invoke_all } - end - end - end - end - - assert_equal 1, @sequence_step - assert_match(/DEPRECATION WARNING: `after_bundle` is deprecated/, content) - end - private def action(*args, &block) diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb index 3cffdddd38..f672e301a7 100644 --- a/railties/test/generators/scaffold_generator_test.rb +++ b/railties/test/generators/scaffold_generator_test.rb @@ -5,7 +5,7 @@ require "rails/generators/rails/scaffold/scaffold_generator" class ScaffoldGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper - arguments %w(product_line title:string product:belongs_to user:references) + arguments %w(product_line title:string approved:boolean product:belongs_to user:references) setup :copy_routes @@ -17,6 +17,7 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase assert_file "test/models/product_line_test.rb", /class ProductLineTest < ActiveSupport::TestCase/ assert_file "test/fixtures/product_lines.yml" assert_migration "db/migrate/create_product_lines.rb", /belongs_to :product/ + assert_migration "db/migrate/create_product_lines.rb", /boolean :approved/ assert_migration "db/migrate/create_product_lines.rb", /references :user/ # Route @@ -60,8 +61,8 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase assert_file "test/controllers/product_lines_controller_test.rb" do |test| assert_match(/class ProductLinesControllerTest < ActionDispatch::IntegrationTest/, test) - assert_match(/post product_lines_url, params: \{ product_line: \{ product_id: @product_line\.product_id, title: @product_line\.title, user_id: @product_line\.user_id \} \}/, test) - assert_match(/patch product_line_url\(@product_line\), params: \{ product_line: \{ product_id: @product_line\.product_id, title: @product_line\.title, user_id: @product_line\.user_id \} \}/, test) + assert_match(/post product_lines_url, params: \{ product_line: \{ approved: @product_line\.approved, product_id: @product_line\.product_id, title: @product_line\.title, user_id: @product_line\.user_id \} \}/, test) + assert_match(/patch product_line_url\(@product_line\), params: \{ product_line: \{ approved: @product_line\.approved, product_id: @product_line\.product_id, title: @product_line\.title, user_id: @product_line\.user_id \} \}/, test) end # System tests @@ -69,6 +70,7 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase assert_match(/class ProductLinesTest < ApplicationSystemTestCase/, test) assert_match(/visit product_lines_url/, test) assert_match(/fill_in "Title", with: @product_line\.title/, test) + assert_match(/check "Approved" if @product_line\.approved/, test) assert_match(/assert_text "Product line was successfully updated"/, test) end diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb index 9b980bd52b..26ce487c5f 100644 --- a/railties/test/generators/shared_generator_tests.rb +++ b/railties/test/generators/shared_generator_tests.rb @@ -10,9 +10,9 @@ module SharedGeneratorTests Rails::Generators::AppGenerator.instance_variable_set("@desc", nil) Kernel.silence_warnings do - Thor::Base.shell.send(:attr_accessor, :always_force) + Thor::Base.shell.attr_accessor :always_force @shell = Thor::Base.shell.new - @shell.send(:always_force=, true) + @shell.always_force = true end end @@ -127,6 +127,8 @@ module SharedGeneratorTests "--skip-active-record", "--skip-active-storage", "--skip-action-mailer", + "--skip-action-mailbox", + "--skip-action-text", "--skip-action-cable", "--skip-sprockets" ] @@ -138,6 +140,10 @@ module SharedGeneratorTests assert_file "#{application_path}/config/application.rb", /^# require\s+["']active_storage\/engine["']/ assert_file "#{application_path}/config/application.rb", /^require\s+["']action_controller\/railtie["']/ assert_file "#{application_path}/config/application.rb", /^# require\s+["']action_mailer\/railtie["']/ + unless generator_class.name == "Rails::Generators::PluginGenerator" + assert_file "#{application_path}/config/application.rb", /^# require\s+["']action_mailbox\/engine["']/ + assert_file "#{application_path}/config/application.rb", /^# require\s+["']action_text\/engine["']/ + end assert_file "#{application_path}/config/application.rb", /^require\s+["']action_view\/railtie["']/ assert_file "#{application_path}/config/application.rb", /^# require\s+["']action_cable\/engine["']/ assert_file "#{application_path}/config/application.rb", /^# require\s+["']sprockets\/railtie["']/ @@ -200,7 +206,7 @@ module SharedGeneratorTests unless generator_class.name == "Rails::Generators::PluginGenerator" assert_file "#{application_path}/app/javascript/packs/application.js" do |content| - assert_match(/^import \* as ActiveStorage from "activestorage"\nActiveStorage.start\(\)/, content) + assert_match(/^require\("@rails\/activestorage"\)\.start\(\)/, content) end end @@ -261,7 +267,7 @@ module SharedGeneratorTests assert_file "#{application_path}/config/application.rb", /#\s+require\s+["']active_storage\/engine["']/ assert_file "#{application_path}/app/javascript/packs/application.js" do |content| - assert_no_match(/^import * as ActiveStorage from "activestorage"\nActiveStorage.start\(\)/, content) + assert_no_match(/^require\("@rails\/activestorage"\)\.start\(\)/, content) end assert_file "#{application_path}/config/environments/development.rb" do |content| @@ -336,13 +342,15 @@ module SharedGeneratorTests end def test_generator_for_yarn + skip "#34009 disabled JS by default for plugins" if generator_class.name == "Rails::Generators::PluginGenerator" run_generator assert_file "#{application_path}/package.json", /dependencies/ + assert_file "#{application_path}/bin/yarn" assert_file "#{application_path}/config/initializers/assets.rb", /node_modules/ end def test_generator_for_yarn_skipped - run_generator([destination_root, "--skip-yarn"]) + run_generator([destination_root, "--skip-javascript"]) assert_no_file "#{application_path}/package.json" assert_no_file "#{application_path}/bin/yarn" diff --git a/railties/test/generators/system_test_generator_test.rb b/railties/test/generators/system_test_generator_test.rb index efa70a050b..5742ba444d 100644 --- a/railties/test/generators/system_test_generator_test.rb +++ b/railties/test/generators/system_test_generator_test.rb @@ -16,4 +16,18 @@ class SystemTestGeneratorTest < Rails::Generators::TestCase run_generator %w(admin/user) assert_file "test/system/admin/users_test.rb", /class Admin::UsersTest < ApplicationSystemTestCase/ end + + def test_test_name_is_pluralized + run_generator %w(user) + + assert_no_file "test/system/user_test.rb" + assert_file "test/system/users_test.rb" + end + + def test_test_suffix_is_not_duplicated + run_generator %w(users_test) + + assert_no_file "test/system/users_test_test.rb" + assert_file "test/system/users_test.rb" + end end diff --git a/railties/test/generators_test.rb b/railties/test/generators_test.rb index f98c1f78f7..abdc04a8d3 100644 --- a/railties/test/generators_test.rb +++ b/railties/test/generators_test.rb @@ -28,6 +28,7 @@ class GeneratorsTest < Rails::Generators::TestCase output = capture(:stdout) { Rails::Generators.invoke name } assert_match "Could not find generator '#{name}'", output assert_match "`rails generate --help`", output + assert_no_match "Maybe you meant", output end def test_generator_suggestions diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index d4eed69a87..3f1638a516 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -197,6 +197,7 @@ module TestHelpers end add_to_config <<-RUBY + config.hosts << proc { true } config.eager_load = false config.session_store :cookie_store, key: "_myapp_session" config.active_support.deprecation = :log @@ -220,6 +221,7 @@ module TestHelpers @app = Class.new(Rails::Application) do def self.name; "RailtiesTestApp"; end end + @app.config.hosts << proc { true } @app.config.eager_load = false @app.config.session_store :cookie_store, key: "_myapp_session" @app.config.active_support.deprecation = :log @@ -419,6 +421,10 @@ module TestHelpers file_name end + def app_dir(path) + FileUtils.mkdir_p("#{app_path}/#{path}") + end + def remove_file(path) FileUtils.rm_rf "#{app_path}/#{path}" end @@ -428,7 +434,7 @@ module TestHelpers end def use_frameworks(arr) - to_remove = [:actionmailer, :activerecord, :activestorage, :activejob] - arr + to_remove = [:actionmailer, :activerecord, :activestorage, :activejob, :actionmailbox] - arr if to_remove.include?(:activerecord) remove_from_config "config.active_record.*" @@ -452,18 +458,21 @@ module TestHelpers end end end + + module Reload + def reload + ActiveSupport::Dependencies.clear + end + end end class ActiveSupport::TestCase include TestHelpers::Paths include TestHelpers::Rack include TestHelpers::Generation + include TestHelpers::Reload include ActiveSupport::Testing::Stream include ActiveSupport::Testing::MethodCallAssertions - - def frozen_error_class - Object.const_defined?(:FrozenError) ? FrozenError : RuntimeError - end end # Create a scope and build a fixture rails app @@ -474,21 +483,17 @@ Module.new do FileUtils.rm_rf(app_template_path) FileUtils.mkdir_p(app_template_path) - Dir.chdir "#{RAILS_FRAMEWORK_ROOT}/actionview" do - `yarn build` - end - - `#{Gem.ruby} #{RAILS_FRAMEWORK_ROOT}/railties/exe/rails new #{app_template_path} --skip-gemfile --skip-listen --no-rc` + `#{Gem.ruby} #{RAILS_FRAMEWORK_ROOT}/railties/exe/rails new #{app_template_path} --skip-bundle --skip-listen --no-rc --skip-webpack-install` File.open("#{app_template_path}/config/boot.rb", "w") do |f| f.puts "require 'rails/all'" end - Dir.chdir(app_template_path) { `yarn add https://github.com/rails/webpacker.git` } # Use the latest version. - - # Manually install `webpack` as bin symlinks are not created for subdependencies - # in workspaces. See https://github.com/yarnpkg/yarn/issues/4964 - Dir.chdir(app_template_path) { `yarn add webpack@4.17.1 --tilde` } - Dir.chdir(app_template_path) { `yarn add webpack-cli` } + assets_path = "#{RAILS_FRAMEWORK_ROOT}/railties/test/isolation/assets" + FileUtils.cp("#{assets_path}/package.json", "#{app_template_path}/package.json") + FileUtils.cp("#{assets_path}/config/webpacker.yml", "#{app_template_path}/config/webpacker.yml") + FileUtils.cp_r("#{assets_path}/config/webpack", "#{app_template_path}/config/webpack") + FileUtils.ln_s("#{assets_path}/node_modules", "#{app_template_path}/node_modules") + FileUtils.chdir(app_template_path) { `bin/rails webpacker:binstubs` } # Fake 'Bundler.require' -- we run using the repo's Gemfile, not an # app-specific one: we don't want to require every gem that lists. @@ -506,6 +511,8 @@ Module.new do require "action_view" require "active_storage" require "action_cable" + require "action_mailbox" + require "action_text" require "sprockets" require "action_view/helpers" diff --git a/railties/test/isolation/assets/config/webpack/development.js b/railties/test/isolation/assets/config/webpack/development.js new file mode 100644 index 0000000000..395290f431 --- /dev/null +++ b/railties/test/isolation/assets/config/webpack/development.js @@ -0,0 +1,3 @@ +process.env.NODE_ENV = process.env.NODE_ENV || 'development' +const { environment } = require('@rails/webpacker') +module.exports = environment.toWebpackConfig() diff --git a/railties/test/isolation/assets/config/webpack/production.js b/railties/test/isolation/assets/config/webpack/production.js new file mode 100644 index 0000000000..d064a6a7fb --- /dev/null +++ b/railties/test/isolation/assets/config/webpack/production.js @@ -0,0 +1,3 @@ +process.env.NODE_ENV = process.env.NODE_ENV || 'production' +const { environment } = require('@rails/webpacker') +module.exports = environment.toWebpackConfig() diff --git a/railties/test/isolation/assets/config/webpack/test.js b/railties/test/isolation/assets/config/webpack/test.js new file mode 100644 index 0000000000..395290f431 --- /dev/null +++ b/railties/test/isolation/assets/config/webpack/test.js @@ -0,0 +1,3 @@ +process.env.NODE_ENV = process.env.NODE_ENV || 'development' +const { environment } = require('@rails/webpacker') +module.exports = environment.toWebpackConfig() diff --git a/railties/test/isolation/assets/config/webpacker.yml b/railties/test/isolation/assets/config/webpacker.yml new file mode 100644 index 0000000000..0b1f43a407 --- /dev/null +++ b/railties/test/isolation/assets/config/webpacker.yml @@ -0,0 +1,8 @@ +default: &default + check_yarn_integrity: false +development: + <<: *default +test: + <<: *default +production: + <<: *default diff --git a/railties/test/isolation/assets/package.json b/railties/test/isolation/assets/package.json new file mode 100644 index 0000000000..7c34450fe0 --- /dev/null +++ b/railties/test/isolation/assets/package.json @@ -0,0 +1,11 @@ +{ + "name": "dummy", + "private": true, + "dependencies": { + "@rails/actioncable": "file:../../../../actioncable", + "@rails/activestorage": "file:../../../../activestorage", + "@rails/ujs": "file:../../../../actionview", + "@rails/webpacker": "https://github.com/rails/webpacker.git", + "turbolinks": "^5.2.0" + } +} diff --git a/railties/test/path_generation_test.rb b/railties/test/path_generation_test.rb index 849b183b37..0c1ee259b0 100644 --- a/railties/test/path_generation_test.rb +++ b/railties/test/path_generation_test.rb @@ -66,7 +66,7 @@ class PathGenerationTest < ActiveSupport::TestCase super app = self @routes = TestSet.new ->(c) { app.controller = c } - secrets.secret_token = "foo" + secrets.secret_key_base = "foo" end def app; routes; end } diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 4ac8f8d741..69f6e34d58 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -87,11 +87,10 @@ module RailtiesTest end RUBY + restrict_frameworks boot_rails Dir.chdir(app_path) do - # Install Active Storage migration file first so as not to affect test. - `bundle exec rake active_storage:install` output = `bundle exec rake bukkits:install:migrations` ["CreateUsers", "AddLastNameToUsers", "CreateSessions"].each do |migration_name| @@ -174,11 +173,10 @@ module RailtiesTest class CreateKeys < ActiveRecord::Migration::Current; end RUBY + restrict_frameworks boot_rails Dir.chdir(app_path) do - # Install Active Storage migration file first so as not to affect test. - `bundle exec rake active_storage:install` output = `bundle exec rake railties:install:migrations`.split("\n") assert_match(/Copied migration \d+_create_users\.core_engine\.rb from core_engine/, output.first) @@ -706,25 +704,27 @@ YAML RUBY @plugin.write "app/controllers/bukkits/foo_controller.rb", <<-RUBY - class Bukkits::FooController < ActionController::Base - def index - render inline: "<%= help_the_engine %>" - end + module Bukkits + class FooController < ActionController::Base + def index + render inline: "<%= help_the_engine %>" + end - def show - render plain: foo_path - end + def show + render plain: foo_path + end - def from_app - render inline: "<%= (self.respond_to?(:bar_path) || self.respond_to?(:something)) %>" - end + def from_app + render inline: "<%= (self.respond_to?(:bar_path) || self.respond_to?(:something)) %>" + end - def routes_helpers_in_view - render inline: "<%= foo_path %>, <%= main_app.bar_path %>" - end + def routes_helpers_in_view + render inline: "<%= foo_path %>, <%= main_app.bar_path %>" + end - def polymorphic_path_without_namespace - render plain: polymorphic_path(Post.new) + def polymorphic_path_without_namespace + render plain: polymorphic_path(Post.new) + end end end RUBY @@ -879,6 +879,18 @@ YAML assert Bukkits::Engine.config.bukkits_seeds_loaded end + test "jobs are ran inline while loading seeds" do + app_file "db/seeds.rb", <<-RUBY + Rails.application.config.seed_queue_adapter = ActiveJob::Base.queue_adapter + RUBY + + boot_rails + Rails.application.load_seed + + assert_instance_of ActiveJob::QueueAdapters::InlineAdapter, Rails.application.config.seed_queue_adapter + assert_instance_of ActiveJob::QueueAdapters::AsyncAdapter, ActiveJob::Base.queue_adapter + end + test "skips nonexistent seed data" do FileUtils.rm "#{app_path}/db/seeds.rb" boot_rails @@ -1497,5 +1509,25 @@ YAML def app Rails.application end + + # Restrict frameworks to load in order to avoid engine frameworks affect tests. + def restrict_frameworks + remove_from_config("require 'rails/all'") + remove_from_config("require_relative 'boot'") + remove_from_env_config("development", "config.active_storage.*") + frameworks = <<~RUBY + require "rails" + require "active_model/railtie" + require "active_job/railtie" + require "active_record/railtie" + require "action_controller/railtie" + require "action_mailer/railtie" + require "action_view/railtie" + require "sprockets/railtie" + require "rails/test_unit/railtie" + RUBY + environment = File.read("#{app_path}/config/application.rb") + File.open("#{app_path}/config/application.rb", "w") { |f| f.puts frameworks + "\n" + environment } + end end end diff --git a/railties/test/railties/mounted_engine_test.rb b/railties/test/railties/mounted_engine_test.rb index 48f0fbc80f..9755823e51 100644 --- a/railties/test/railties/mounted_engine_test.rb +++ b/railties/test/railties/mounted_engine_test.rb @@ -232,7 +232,7 @@ module ApplicationTests get "/someone/blog/generate_application_route" assert_equal "/", last_response.body - get "/somone/blog/application_route_in_view" + get "/someone/blog/application_route_in_view" assert_equal "/", last_response.body # test generating engine's route from other engine @@ -258,8 +258,8 @@ module ApplicationTests assert_equal "http://example.org/anonymous/blog/posts/44", last_response.body # test that correct path is generated for the same polymorphic_path call in an engine - get "/somone/blog/engine_polymorphic_path" - assert_equal "/somone/blog/posts/44", last_response.body + get "/someone/blog/engine_polymorphic_path" + assert_equal "/someone/blog/posts/44", last_response.body # and in an application get "/application_polymorphic_path" diff --git a/railties/test/railties/railtie_test.rb b/railties/test/railties/railtie_test.rb index 7c3d1e3759..b9725ca0ad 100644 --- a/railties/test/railties/railtie_test.rb +++ b/railties/test/railties/railtie_test.rb @@ -25,12 +25,10 @@ module RailtiesTest end test "Railtie provides railtie_name" do - begin - class ::FooBarBaz < Rails::Railtie ; end - assert_equal "foo_bar_baz", FooBarBaz.railtie_name - ensure - Object.send(:remove_const, :"FooBarBaz") - end + class ::FooBarBaz < Rails::Railtie ; end + assert_equal "foo_bar_baz", FooBarBaz.railtie_name + ensure + Object.send(:remove_const, :"FooBarBaz") end test "railtie_name can be set manually" do @@ -203,14 +201,12 @@ module RailtiesTest end test "we can change our environment if we want to" do - begin - original_env = Rails.env - Rails.env = "foo" - assert_equal("foo", Rails.env) - ensure - Rails.env = original_env - assert_equal(original_env, Rails.env) - end + original_env = Rails.env + Rails.env = "foo" + assert_equal("foo", Rails.env) + ensure + Rails.env = original_env + assert_equal(original_env, Rails.env) end end end diff --git a/railties/test/secrets_test.rb b/railties/test/secrets_test.rb index 06877bc76a..133d851819 100644 --- a/railties/test/secrets_test.rb +++ b/railties/test/secrets_test.rb @@ -35,15 +35,13 @@ class Rails::SecretsTest < ActiveSupport::TestCase test "reading with ENV variable" do run_secrets_generator do - begin - old_key = ENV["RAILS_MASTER_KEY"] - ENV["RAILS_MASTER_KEY"] = IO.binread("config/secrets.yml.key").strip - FileUtils.rm("config/secrets.yml.key") - - assert_match "# production:\n# external_api_key:", Rails::Secrets.read - ensure - ENV["RAILS_MASTER_KEY"] = old_key - end + old_key = ENV["RAILS_MASTER_KEY"] + ENV["RAILS_MASTER_KEY"] = IO.binread("config/secrets.yml.key").strip + FileUtils.rm("config/secrets.yml.key") + + assert_match "# production:\n# external_api_key:", Rails::Secrets.read + ensure + ENV["RAILS_MASTER_KEY"] = old_key end end |