diff options
Diffstat (limited to 'railties/test')
31 files changed, 800 insertions, 54 deletions
diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index a80581211b..651897d8f3 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -311,7 +311,7 @@ module ApplicationTests manifest = Dir["#{app_path}/public/assets/.sprockets-manifest-*.json"].first assets = ActiveSupport::JSON.decode(File.read(manifest)) - assert asset_path = assets["assets"].find { |(k, _)| k && k =~ /.png/ }[1] + assert asset_path = assets["assets"].find { |(k, _)| /.png/.match?(k) }[1] # Load app env app "development" @@ -491,7 +491,6 @@ module ApplicationTests end private - def app_with_assets_in_view app_file "app/assets/javascripts/application.js", "//= require_tree ." app_file "app/assets/javascripts/xmlhr.js", "function f1() { alert(); }" diff --git a/railties/test/application/bin_setup_test.rb b/railties/test/application/bin_setup_test.rb index aa0da0931d..d84ab61cf9 100644 --- a/railties/test/application/bin_setup_test.rb +++ b/railties/test/application/bin_setup_test.rb @@ -31,7 +31,7 @@ module ApplicationTests Dir.chdir(app_path) do # SQLite3 seems to auto-create the database on first checkout. rails "db:system:change", "--to=postgresql" - rails "db:drop" + rails "db:drop", allow_failure: true app_file "db/schema.rb", "" diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 7c613585e0..cca86bc13a 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -456,7 +456,7 @@ module ApplicationTests test "filter_parameters should be able to set via config.filter_parameters" do add_to_config <<-RUBY config.filter_parameters += [ :foo, 'bar', lambda { |key, value| - value = value.reverse if key =~ /baz/ + value = value.reverse if /baz/.match?(key) }] RUBY @@ -790,7 +790,7 @@ module ApplicationTests end get "/" - assert last_response.body =~ /csrf\-param/ + assert /csrf\-param/.match?(last_response.body) end test "default form builder specified as a string" do @@ -1607,6 +1607,13 @@ module ApplicationTests assert_not_nil Rails::SourceAnnotationExtractor::Annotation.extensions[/\.(coffee)$/] end + test "config.default_log_file returns a File instance" do + app "development" + + assert_instance_of File, app.config.default_log_file + assert_equal Rails.application.config.paths["log"].first, app.config.default_log_file.path + end + test "rake_tasks block works at instance level" do app_file "config/environments/development.rb", <<-RUBY Rails.application.configure do @@ -1701,7 +1708,7 @@ module ApplicationTests 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" + assert_not_operator path, :ends_with?, "app/#{Rails.configuration.webpacker_path}" end end @@ -1786,6 +1793,11 @@ module ApplicationTests assert_equal [X, D], C.descendants end + test "load_database_yaml returns blank hash if configuration file is blank" do + app_file "config/database.yml", "" + app "development" + assert_equal({}, Rails.application.config.load_database_yaml) + end test "raises with proper error message if no database configuration found" do FileUtils.rm("#{app_path}/config/database.yml") @@ -2429,6 +2441,33 @@ module ApplicationTests assert_nil ActiveStorage.queues[:purge] end + test "ActionDispatch::Response.return_only_media_type_on_content_type is false by default" do + app "development" + + assert_equal false, ActionDispatch::Response.return_only_media_type_on_content_type + end + + test "ActionDispatch::Response.return_only_media_type_on_content_type is true 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 true, ActionDispatch::Response.return_only_media_type_on_content_type + end + + test "ActionDispatch::Response.return_only_media_type_on_content_type 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_dispatch.return_only_media_type_on_content_type = true + RUBY + + app "development" + + assert_equal true, ActionDispatch::Response.return_only_media_type_on_content_type + end + test "ActionMailbox.logger is Rails.logger by default" do app "development" @@ -2554,6 +2593,21 @@ module ApplicationTests MESSAGE end + test "ActiveStorage.draw_routes can be configured via config.active_storage.draw_routes" do + app_file "config/environments/development.rb", <<-RUBY + Rails.application.configure do + config.active_storage.draw_routes = false + end + RUBY + + output = rails("routes") + assert_not_includes(output, "rails_service_blob") + assert_not_includes(output, "rails_blob_representation") + assert_not_includes(output, "rails_disk_service") + assert_not_includes(output, "update_rails_disk_service") + assert_not_includes(output, "rails_direct_uploads") + end + test "hosts include .localhost in development" do app "development" assert_includes Rails.application.config.hosts, ".localhost" diff --git a/railties/test/application/content_security_policy_test.rb b/railties/test/application/content_security_policy_test.rb index 0d28df16f8..0bb6ee917a 100644 --- a/railties/test/application/content_security_policy_test.rb +++ b/railties/test/application/content_security_policy_test.rb @@ -119,6 +119,38 @@ module ApplicationTests assert_policy "default-src 'self' https:", report_only: true end + test "global content security policy nonce directives in an initializer" do + controller :pages, <<-RUBY + class PagesController < ApplicationController + def index + render html: "<h1>Welcome to Rails!</h1>" + end + end + RUBY + + app_file "config/initializers/content_security_policy.rb", <<-RUBY + Rails.application.config.content_security_policy do |p| + p.default_src :self, :https + p.script_src :self, :https + p.style_src :self, :https + end + + Rails.application.config.content_security_policy_nonce_generator = proc { "iyhD0Yc0W+c=" } + Rails.application.config.content_security_policy_nonce_directives = %w(script-src) + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + root to: "pages#index" + end + RUBY + + app("development") + + get "/" + assert_policy "default-src 'self' https:; script-src 'self' https: 'nonce-iyhD0Yc0W+c='; style-src 'self' https:" + end + test "override content security policy in a controller" do controller :pages, <<-RUBY class PagesController < ApplicationController @@ -204,7 +236,6 @@ module ApplicationTests end private - def assert_policy(expected, report_only: false) assert_equal 200, last_response.status diff --git a/railties/test/application/feature_policy_test.rb b/railties/test/application/feature_policy_test.rb new file mode 100644 index 0000000000..e751d782ee --- /dev/null +++ b/railties/test/application/feature_policy_test.rb @@ -0,0 +1,191 @@ +# frozen_string_literal: true + +require "isolation/abstract_unit" +require "rack/test" + +module ApplicationTests + class FeaturePolicyTest < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation + include Rack::Test::Methods + + def setup + build_app + end + + def teardown + teardown_app + end + + test "feature policy is not enabled by default" do + controller :pages, <<-RUBY + class PagesController < ApplicationController + def index + render html: "<h1>Welcome to Rails!</h1>" + end + end + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + root to: "pages#index" + end + RUBY + + app("development") + + get "/" + assert_nil last_response.headers["Feature-Policy"] + end + + test "global feature policy in an initializer" do + controller :pages, <<-RUBY + class PagesController < ApplicationController + def index + render html: "<h1>Welcome to Rails!</h1>" + end + end + RUBY + + app_file "config/initializers/feature_policy.rb", <<-RUBY + Rails.application.config.feature_policy do |p| + p.geolocation :none + end + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + root to: "pages#index" + end + RUBY + + app("development") + + get "/" + assert_policy "geolocation 'none'" + end + + test "override feature policy using same directive in a controller" do + controller :pages, <<-RUBY + class PagesController < ApplicationController + feature_policy do |p| + p.geolocation "https://example.com" + end + + def index + render html: "<h1>Welcome to Rails!</h1>" + end + end + RUBY + + app_file "config/initializers/feature_policy.rb", <<-RUBY + Rails.application.config.feature_policy do |p| + p.geolocation :none + end + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + root to: "pages#index" + end + RUBY + + app("development") + + get "/" + assert_policy "geolocation https://example.com" + end + + test "override feature policy by unsetting a directive in a controller" do + controller :pages, <<-RUBY + class PagesController < ApplicationController + feature_policy do |p| + p.geolocation nil + end + + def index + render html: "<h1>Welcome to Rails!</h1>" + end + end + RUBY + + app_file "config/initializers/feature_policy.rb", <<-RUBY + Rails.application.config.feature_policy do |p| + p.geolocation :none + end + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + root to: "pages#index" + end + RUBY + + app("development") + + get "/" + assert_equal 200, last_response.status + assert_nil last_response.headers["Feature-Policy"] + end + + test "override feature policy using different directives in a controller" do + controller :pages, <<-RUBY + class PagesController < ApplicationController + feature_policy do |p| + p.geolocation nil + p.payment "https://secure.example.com" + p.autoplay :none + end + + def index + render html: "<h1>Welcome to Rails!</h1>" + end + end + RUBY + + app_file "config/initializers/feature_policy.rb", <<-RUBY + Rails.application.config.feature_policy do |p| + p.geolocation :none + end + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + root to: "pages#index" + end + RUBY + + app("development") + + get "/" + assert_policy "payment https://secure.example.com; autoplay 'none'" + end + + test "global feature policy added to rack app" do + app_file "config/initializers/feature_policy.rb", <<-RUBY + Rails.application.config.feature_policy do |p| + p.payment :none + end + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + app = ->(env) { + [200, { "Content-Type" => "text/html" }, ["<p>Hello, World!</p>"]] + } + root to: app + end + RUBY + + app("development") + + get "/" + assert_policy "payment 'none'" + end + + private + def assert_policy(expected) + assert_equal 200, last_response.status + assert_equal expected, last_response.headers["Feature-Policy"] + end + end +end diff --git a/railties/test/application/generators_test.rb b/railties/test/application/generators_test.rb index e5e557d204..8ec26db772 100644 --- a/railties/test/application/generators_test.rb +++ b/railties/test/application/generators_test.rb @@ -198,5 +198,15 @@ module ApplicationTests assert_no_match "active_record:migration", output end end + + test "skip collision check" do + rails("generate", "model", "post", "title:string") + + output = rails("generate", "model", "post", "title:string", "body:string") + assert_match(/The name 'Post' is either already used in your application or reserved/, output) + + output = rails("generate", "model", "post", "title:string", "body:string", "--skip-collision-check") + assert_no_match(/The name 'Post' is either already used in your application or reserved/, output) + end end end diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index a35247fc43..05978e1d99 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -218,8 +218,9 @@ module ApplicationTests rails %w(generate model post title:string) rails %w(db:migrate db:schema:cache:dump) require "#{app_path}/config/environment" - ActiveRecord::Base.connection.drop_table("posts") # force drop posts table for test. assert ActiveRecord::Base.connection.schema_cache.data_sources("posts") + ensure + ActiveRecord::Base.connection.drop_table("posts", if_exists: true) # force drop posts table for test. end test "expire schema cache dump" do diff --git a/railties/test/application/loading_test.rb b/railties/test/application/loading_test.rb index 9c98489590..9ab400acfc 100644 --- a/railties/test/application/loading_test.rb +++ b/railties/test/application/loading_test.rb @@ -116,7 +116,7 @@ class LoadingTest < ActiveSupport::TestCase RUBY app_file "app/models/post.rb", <<-MODEL - class Post < ActiveRecord::Base + class Post < ApplicationRecord end MODEL @@ -133,11 +133,12 @@ class LoadingTest < ActiveSupport::TestCase require "#{rails_root}/config/environment" setup_ar! - assert_equal [ActiveStorage::Blob, ActiveStorage::Attachment, ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata].collect(&:to_s).sort, ActiveRecord::Base.descendants.collect(&:to_s).sort + initial = [ActiveStorage::Blob, ActiveStorage::Attachment, ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata, ApplicationRecord, "primary::SchemaMigration"].collect(&:to_s).sort + assert_equal initial, ActiveRecord::Base.descendants.collect(&:to_s).sort get "/load" - assert_equal [ActiveStorage::Blob, ActiveStorage::Attachment, ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata, Post].collect(&:to_s).sort, ActiveRecord::Base.descendants.collect(&:to_s).sort + assert_equal [Post].collect(&:to_s).sort, ActiveRecord::Base.descendants.collect(&:to_s).sort - initial get "/unload" - assert_equal [ActiveStorage::Blob, ActiveStorage::Attachment, ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata].collect(&:to_s).sort, ActiveRecord::Base.descendants.collect(&:to_s).sort + assert_equal ["ActiveRecord::InternalMetadata", "ActiveRecord::SchemaMigration", "primary::SchemaMigration"], ActiveRecord::Base.descendants.collect(&:to_s).sort.uniq end test "initialize cant be called twice" do @@ -454,7 +455,6 @@ class LoadingTest < ActiveSupport::TestCase end private - def setup_ar! ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") ActiveRecord::Migration.verbose = false diff --git a/railties/test/application/middleware/exceptions_test.rb b/railties/test/application/middleware/exceptions_test.rb index 17df78ed4e..5fae521937 100644 --- a/railties/test/application/middleware/exceptions_test.rb +++ b/railties/test/application/middleware/exceptions_test.rb @@ -136,5 +136,21 @@ module ApplicationTests assert_match(/boooom/, last_response.body) assert_match(/測試テスト시험/, last_response.body) end + + test "displays diagnostics message when malformed query parameters are provided" do + controller :foo, <<-RUBY + class FooController < ActionController::Base + def index + end + end + RUBY + + app.config.action_dispatch.show_exceptions = true + app.config.consider_all_requests_local = true + + get "/foo?x[y]=1&x[y][][w]=2" + assert_equal 400, last_response.status + assert_match "Invalid query parameters", last_response.body + end end end diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index 54b2e95d75..e93f2f5aa4 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -46,6 +46,7 @@ module ApplicationTests "ActionDispatch::Session::CookieStore", "ActionDispatch::Flash", "ActionDispatch::ContentSecurityPolicy::Middleware", + "ActionDispatch::FeaturePolicy::Middleware", "Rack::Head", "Rack::ConditionalGet", "Rack::ETag", @@ -309,7 +310,6 @@ module ApplicationTests end private - def boot! require "#{app_path}/config/environment" end diff --git a/railties/test/application/rake/dbs_test.rb b/railties/test/application/rake/dbs_test.rb index 258066a7e6..c9931c45a6 100644 --- a/railties/test/application/rake/dbs_test.rb +++ b/railties/test/application/rake/dbs_test.rb @@ -40,6 +40,15 @@ module ApplicationTests end end + def db_create_with_warning(expected_database) + Dir.chdir(app_path) do + output = rails("db:create") + assert_match(/Rails couldn't infer whether you are using multiple databases/, output) + assert_match(/Created database/, output) + assert File.exist?(expected_database) + end + end + test "db:create and db:drop without database URL" do require "#{app_path}/config/environment" db_create_and_drop ActiveRecord::Base.configurations[Rails.env]["database"] @@ -86,6 +95,25 @@ module ApplicationTests db_create_and_drop("db/development.sqlite3", environment_loaded: false) end + test "db:create and db:drop show warning but doesn't raise errors when loading YAML with alias ERB" do + app_file "config/database.yml", <<-YAML + sqlite: &sqlite + adapter: sqlite3 + database: db/development.sqlite3 + + development: + <<: *<%= ENV["DB"] || "sqlite" %> + YAML + + app_file "config/environments/development.rb", <<-RUBY + Rails.application.configure do + config.database = "db/development.sqlite3" + end + RUBY + + db_create_with_warning("db/development.sqlite3") + end + test "db:create and db:drop don't raise errors when loading YAML containing conditional statements in ERB" do app_file "config/database.yml", <<-YAML development: @@ -122,6 +150,39 @@ module ApplicationTests db_create_and_drop("db/development.sqlite3", environment_loaded: false) end + test "db:create and db:drop dont raise errors when loading YAML with FIXME ERB" do + app_file "config/database.yml", <<-YAML + development: + <%= Rails.application.config.database ? 'database: db/development.sqlite3' : 'database: db/development.sqlite3' %> + adapter: sqlite3 + YAML + + app_file "config/environments/development.rb", <<-RUBY + Rails.application.configure do + config.database = "db/development.sqlite3" + end + RUBY + + db_create_and_drop("db/development.sqlite3", environment_loaded: false) + end + + test "db:create and db:drop don't raise errors when loading YAML which contains a key's value as an ERB statement" do + app_file "config/database.yml", <<-YAML + development: + database: <%= Rails.application.config.database ? 'db/development.sqlite3' : 'db/development.sqlite3' %> + custom_option: <%= ENV['CUSTOM_OPTION'] %> + adapter: sqlite3 + YAML + + app_file "config/environments/development.rb", <<-RUBY + Rails.application.configure do + config.database = "db/development.sqlite3" + end + RUBY + + db_create_and_drop("db/development.sqlite3", environment_loaded: false) + end + def with_database_existing Dir.chdir(app_path) do set_database_url @@ -569,6 +630,22 @@ module ApplicationTests assert_match(/CreateRecipes: migrated/, output) end end + + test "db:prepare does not touch schema when dumping is disabled" do + Dir.chdir(app_path) do + rails "generate", "model", "book", "title:string" + rails "db:create", "db:migrate" + + app_file "db/schema.rb", "Not touched" + app_file "config/initializers/disable_dumping_schema.rb", <<-RUBY + Rails.application.config.active_record.dump_schema_after_migration = false + RUBY + + rails "db:prepare" + + assert_equal("Not touched", File.read("db/schema.rb").strip) + end + end end end end diff --git a/railties/test/application/rake/multi_dbs_test.rb b/railties/test/application/rake/multi_dbs_test.rb index 31ea2246a9..2606e64424 100644 --- a/railties/test/application/rake/multi_dbs_test.rb +++ b/railties/test/application/rake/multi_dbs_test.rb @@ -299,10 +299,56 @@ module ApplicationTests db_migrate_and_schema_cache_dump_and_schema_cache_clear end + test "db:abort_if_pending_migrations works on all databases" do + require "#{app_path}/config/environment" + + app_file "db/animals_migrate/02_two_migration.rb", <<-MIGRATION + class TwoMigration < ActiveRecord::Migration::Current + end + MIGRATION + + output = rails("db:abort_if_pending_migrations", allow_failure: true) + assert_match(/You have 1 pending migration/, output) + end + + test "db:abort_if_pending_migrations:namespace works" do + require "#{app_path}/config/environment" + + app_file "db/animals_migrate/02_two_migration.rb", <<-MIGRATION + class TwoMigration < ActiveRecord::Migration::Current + end + MIGRATION + + output = rails("db:abort_if_pending_migrations:primary") + assert_no_match(/You have \d+ pending migration/, output) + output = rails("db:abort_if_pending_migrations:animals", allow_failure: true) + assert_match(/You have 1 pending migration/, output) + end + test "db:prepare works on all databases" do require "#{app_path}/config/environment" db_prepare end + + test "db:prepare setups missing database without clearing existing one" do + require "#{app_path}/config/environment" + Dir.chdir(app_path) do + # Bug not visible on SQLite3. Can be simplified when https://github.com/rails/rails/issues/36383 resolved + use_postgresql(multi_db: true) + generate_models_for_animals + + rails "db:create:animals", "db:migrate:animals", "db:create:primary", "db:migrate:primary", "db:schema:dump" + rails "db:drop:primary" + Dog.create! + output = rails("db:prepare") + + assert_match(/Created database/, output) + assert_equal 1, Dog.count + ensure + Dog.connection.disconnect! + rails "db:drop" rescue nil + end + end end end end diff --git a/railties/test/application/rake/notes_test.rb b/railties/test/application/rake/notes_test.rb index 60802ef7c4..47822e55b9 100644 --- a/railties/test/application/rake/notes_test.rb +++ b/railties/test/application/rake/notes_test.rb @@ -159,7 +159,6 @@ module ApplicationTests end private - def run_rake_notes(command = "bin/rake notes") Dir.chdir(app_path) do output = `#{command}` diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index fe56e3d076..e8456e8c19 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -162,7 +162,6 @@ module ApplicationTests rails "generate", "scaffold", "user", "username:string", "password:string" with_rails_env("test") do rails("db:migrate") - rails("webpacker:compile") end output = rails("test") @@ -194,7 +193,6 @@ module ApplicationTests rails "generate", "scaffold", "LineItems", "product:references", "cart:belongs_to" with_rails_env("test") do rails("db:migrate") - rails("webpacker:compile") end output = rails("test") diff --git a/railties/test/application/system_test_case_test.rb b/railties/test/application/system_test_case_test.rb new file mode 100644 index 0000000000..d15a0d9210 --- /dev/null +++ b/railties/test/application/system_test_case_test.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require "isolation/abstract_unit" +require "rack/test" + +class SystemTestCaseTest < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation + + def setup + build_app + end + + def teardown + teardown_app + end + + test "url helpers are delegated to a proxy class" do + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + get 'foo', to: 'foo#index', as: 'test_foo' + end + RUBY + + app("test") + + assert_not_includes(ActionDispatch::SystemTestCase.runnable_methods, :test_foo_url) + end + + test "system tests set the Capybara host in the url_options by default" do + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + get 'foo', to: 'foo#index', as: 'test_foo' + end + RUBY + + app("test") + system_test = ActionDispatch::SystemTestCase.new("my_test") + previous_app_host = ::Capybara.app_host + ::Capybara.app_host = "https://my_test_example.com" + + assert_equal("https://my_test_example.com/foo", system_test.test_foo_url) + ensure + ::Capybara.app_host = previous_app_host + end +end diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb index 1ab45abcd0..7fc918898b 100644 --- a/railties/test/application/test_runner_test.rb +++ b/railties/test/application/test_runner_test.rb @@ -564,6 +564,24 @@ module ApplicationTests assert_no_match "create_table(:users)", output end + def test_run_in_parallel_with_process_worker_crash + exercise_parallelization_regardless_of_machine_core_count(with: :processes) + + file_name = app_file("test/models/parallel_test.rb", <<-RUBY) + require 'test_helper' + + class ParallelTest < ActiveSupport::TestCase + def test_crash + Kernel.exit 1 + end + end + RUBY + + output = run_test_command(file_name) + + assert_match %r{Queue not empty, but all workers have finished. This probably means that a worker crashed and 1 tests were missed.}, output + end + def test_run_in_parallel_with_threads exercise_parallelization_regardless_of_machine_core_count(with: :threads) diff --git a/railties/test/application/zeitwerk_integration_test.rb b/railties/test/application/zeitwerk_integration_test.rb index 9146222f73..d03fa3d0c6 100644 --- a/railties/test/application/zeitwerk_integration_test.rb +++ b/railties/test/application/zeitwerk_integration_test.rb @@ -98,6 +98,15 @@ class ZeitwerkIntegrationTest < ActiveSupport::TestCase assert_nil deps.safe_constantize("Admin") end + test "autoloaded? and overridden class names" do + invalid_constant_name = Module.new do + def self.name + "primary::SchemaMigration" + end + end + assert_not deps.autoloaded?(invalid_constant_name) + end + test "unloadable constants (main)" do app_file "app/models/user.rb", "class User; end" app_file "app/models/post.rb", "class Post; end" @@ -141,6 +150,35 @@ class ZeitwerkIntegrationTest < ActiveSupport::TestCase assert_empty deps.autoloaded_constants end + [true, false].each do |add_aps_to_lp| + test "require_dependency looks autoload paths up (#{add_aps_to_lp})" do + add_to_config "config.add_autoload_paths_to_load_path = #{add_aps_to_lp}" + app_file "app/models/user.rb", "class User; end" + boot + + assert require_dependency("user") + end + + test "require_dependency handles absolute paths correctly (#{add_aps_to_lp})" do + add_to_config "config.add_autoload_paths_to_load_path = #{add_aps_to_lp}" + app_file "app/models/user.rb", "class User; end" + boot + + assert require_dependency("#{app_path}/app/models/user.rb") + end + + test "require_dependency supports arguments that repond to to_path (#{add_aps_to_lp})" do + add_to_config "config.add_autoload_paths_to_load_path = #{add_aps_to_lp}" + app_file "app/models/user.rb", "class User; end" + boot + + user = Object.new + def user.to_path; "user"; end + + assert require_dependency(user) + end + end + test "eager loading loads the application code" do $zeitwerk_integration_test_user = false $zeitwerk_integration_test_post = false diff --git a/railties/test/commands/console_test.rb b/railties/test/commands/console_test.rb index f6df2b694a..ee4335e31d 100644 --- a/railties/test/commands/console_test.rb +++ b/railties/test/commands/console_test.rb @@ -116,7 +116,6 @@ class Rails::ConsoleTest < ActiveSupport::TestCase private :output private - def start(argv = []) rails_console = Rails::Console.new(app, parse_arguments(argv)) @output = capture(:stdout) { rails_console.start } diff --git a/railties/test/commands/credentials_test.rb b/railties/test/commands/credentials_test.rb index 0ee36081c0..3dec6fbe10 100644 --- a/railties/test/commands/credentials_test.rb +++ b/railties/test/commands/credentials_test.rb @@ -4,6 +4,8 @@ require "isolation/abstract_unit" require "env_helpers" require "rails/command" require "rails/commands/credentials/credentials_command" +require "fileutils" +require "tempfile" class Rails::Command::CredentialsCommandTest < ActiveSupport::TestCase include ActiveSupport::Testing::Isolation, EnvHelpers @@ -88,10 +90,107 @@ class Rails::Command::CredentialsCommandTest < ActiveSupport::TestCase assert_match(/secret_key_base/, output) end + test "edit ask the user to opt in to pretty credentials" do + assert_match(/Would you like to make the credentials diff from git/, run_edit_command) + end + + test "edit doesn't ask the user to opt in to pretty credentials when alreasy asked" do + app_file("tmp/rails_pretty_credentials", "") + + assert_no_match(/Would you like to make the credentials diff from git/, run_edit_command) + end + + test "edit doesn't ask the user to opt in when user already opted in" do + content = <<~EOM + [diff "rails_credentials"] + textconv = bin/rails credentials:show + EOM + app_file(".git/config", content) + + assert_no_match(/Would you like to make the credentials diff from git/, run_edit_command) + end + + test "edit ask the user to opt in to pretty credentials, user accepts" do + file = Tempfile.open("credentials_test") + file.write("y") + file.rewind + + run_edit_command(stdin: file.path) + + git_attributes = app_path(".gitattributes") + expected = <<~EOM + config/credentials/*.yml.enc diff=rails_credentials + config/credentials.yml.enc diff=rails_credentials + EOM + assert(File.exist?(git_attributes)) + assert_equal(expected, File.read(git_attributes)) + Dir.chdir(app_path) do + assert_equal("bin/rails credentials:show\n", `git config --get 'diff.rails_credentials.textconv'`) + end + ensure + file.close! + end + + test "edit ask the user to opt in to pretty credentials, user refuses" do + file = Tempfile.open("credentials_test") + file.write("n") + file.rewind + + run_edit_command(stdin: file.path) + + git_attributes = app_path(".gitattributes") + assert_not(File.exist?(git_attributes)) + ensure + file.close! + end + test "show credentials" do assert_match(/access_key_id: 123/, run_show_command) end + test "show command when argument is provided (from git diff left file)" do + run_edit_command(environment: "development") + + assert_match(/access_key_id: 123/, run_show_command("config/credentials/development.yml.enc")) + end + + test "show command when argument is provided (from git diff right file)" do + run_edit_command(environment: "development") + + dir = Dir.mktmpdir + file_path = File.join(dir, "KnAM4a_development.yml.enc") + file_content = File.read(app_path("config", "credentials", "development.yml.enc")) + File.write(file_path, file_content) + + assert_match(/access_key_id: 123/, run_show_command(file_path)) + ensure + FileUtils.rm_rf(dir) + end + + test "show command when argument is provided (git diff) and filename is the master credentials" do + assert_match(/access_key_id: 123/, run_show_command("config/credentials.yml.enc")) + end + + test "show command when argument is provided (git diff) and master key is not available" do + remove_file "config/master.key" + + raw_content = File.read(app_path("config", "credentials.yml.enc")) + assert_match(raw_content, run_show_command("config/credentials.yml.enc")) + end + + test "show command when argument is provided (git diff) return the raw encrypted content in an error occurs" do + run_edit_command(environment: "development") + + dir = Dir.mktmpdir + file_path = File.join(dir, "20190807development.yml.enc") + file_content = File.read(app_path("config", "credentials", "development.yml.enc")) + File.write(file_path, file_content) + + assert_match(file_content, run_show_command(file_path)) + ensure + FileUtils.rm_rf(dir) + end + test "show command raises error when require_master_key is specified and key does not exist" do remove_file "config/master.key" add_to_config "config.require_master_key = true" @@ -128,8 +227,9 @@ class Rails::Command::CredentialsCommandTest < ActiveSupport::TestCase end end - def run_show_command(environment: nil, **options) + def run_show_command(path = nil, environment: nil, **options) args = environment ? ["--environment", environment] : [] + args.unshift(path) rails "credentials:show", args, **options end end diff --git a/railties/test/commands/dbconsole_test.rb b/railties/test/commands/dbconsole_test.rb index 76a7cd055f..45b72fd909 100644 --- a/railties/test/commands/dbconsole_test.rb +++ b/railties/test/commands/dbconsole_test.rb @@ -275,7 +275,6 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase private :aborted, :output private - def app_db_config(results) Rails.application.config.stub(:database_configuration, results || {}) do yield diff --git a/railties/test/commands/server_test.rb b/railties/test/commands/server_test.rb index b78370a233..c9026e2d95 100644 --- a/railties/test/commands/server_test.rb +++ b/railties/test/commands/server_test.rb @@ -116,6 +116,13 @@ class Rails::Command::ServerCommandTest < ActiveSupport::TestCase end end + def test_environment_with_pidfile + switch_env "PIDFILE", "/tmp/rails.pid" do + options = parse_arguments + assert_equal "/tmp/rails.pid", options[:pid] + end + end + def test_caching_without_option args = [] options = parse_arguments(args) @@ -234,6 +241,12 @@ class Rails::Command::ServerCommandTest < ActiveSupport::TestCase options = parse_arguments(args) assert_equal "127.0.0.1", options[:Host] end + + switch_env "PIDFILE", "/tmp/rails.pid" do + args = ["-P", "/somewhere/else.pid"] + options = parse_arguments(args) + assert_equal "/somewhere/else.pid", options[:pid] + end end def test_records_user_supplied_options @@ -253,6 +266,16 @@ class Rails::Command::ServerCommandTest < ActiveSupport::TestCase server_options = parse_arguments assert_equal [:Host], server_options[:user_supplied_options] end + + switch_env "PORT", "3001" do + server_options = parse_arguments + assert_equal [:Port], server_options[:user_supplied_options] + end + + switch_env "PIDFILE", "/tmp/server.pid" do + server_options = parse_arguments + assert_equal [:pid], server_options[:user_supplied_options] + end end def test_default_options diff --git a/railties/test/configuration/middleware_stack_proxy_test.rb b/railties/test/configuration/middleware_stack_proxy_test.rb index bc72b7f0c9..b67142f4c2 100644 --- a/railties/test/configuration/middleware_stack_proxy_test.rb +++ b/railties/test/configuration/middleware_stack_proxy_test.rb @@ -51,7 +51,6 @@ module Rails end private - def assert_playback(msg_name, args) mock = Minitest::Mock.new mock.expect :send, nil, [msg_name, args] diff --git a/railties/test/env_helpers.rb b/railties/test/env_helpers.rb index 336832b867..e3157e0c77 100644 --- a/railties/test/env_helpers.rb +++ b/railties/test/env_helpers.rb @@ -4,7 +4,6 @@ require "rails" module EnvHelpers private - def with_rails_env(env) Rails.instance_variable_set :@_env, nil switch_env "RAILS_ENV", env do diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb index d913bb5438..5d6d7f1595 100644 --- a/railties/test/generators/actions_test.rb +++ b/railties/test/generators/actions_test.rb @@ -43,7 +43,7 @@ class ActionsTest < Rails::Generators::TestCase def test_add_source_adds_source_to_gemfile run_generator action :add_source, "http://gems.github.com" - assert_file "Gemfile", /source 'http:\/\/gems\.github\.com'/ + assert_file "Gemfile", /source 'http:\/\/gems\.github\.com'\n/ end def test_add_source_with_block_adds_source_to_gemfile_with_gem @@ -51,7 +51,7 @@ class ActionsTest < Rails::Generators::TestCase action :add_source, "http://gems.github.com" do gem "rspec-rails" end - assert_file "Gemfile", /source 'http:\/\/gems\.github\.com' do\n gem 'rspec-rails'\nend/ + assert_file "Gemfile", /\n\nsource 'http:\/\/gems\.github\.com' do\n gem 'rspec-rails'\nend\n\z/ end def test_add_source_with_block_adds_source_to_gemfile_after_gem @@ -60,13 +60,25 @@ class ActionsTest < Rails::Generators::TestCase action :add_source, "http://gems.github.com" do gem "rspec-rails" end - assert_file "Gemfile", /gem 'will-paginate'\nsource 'http:\/\/gems\.github\.com' do\n gem 'rspec-rails'\nend/ + assert_file "Gemfile", /\ngem 'will-paginate'\n\nsource 'http:\/\/gems\.github\.com' do\n gem 'rspec-rails'\nend\n\z/ + end + + def test_add_source_should_create_newline_between_blocks + run_generator + action :add_source, "http://gems.github.com" do + gem "rspec-rails" + end + + action :add_source, "http://gems2.github.com" do + gem "fakeweb" + end + assert_file "Gemfile", /\n\nsource 'http:\/\/gems\.github\.com' do\n gem 'rspec-rails'\nend\n\nsource 'http:\/\/gems2\.github\.com' do\n gem 'fakeweb'\nend\n\z/ end def test_gem_should_put_gem_dependency_in_gemfile run_generator action :gem, "will-paginate" - assert_file "Gemfile", /gem 'will\-paginate'/ + assert_file "Gemfile", /gem 'will\-paginate'\n\z/ end def test_gem_with_version_should_include_version_in_gemfile @@ -141,7 +153,7 @@ class ActionsTest < Rails::Generators::TestCase gem "fakeweb" end - assert_file "Gemfile", /\ngroup :development, :test do\n gem 'rspec-rails'\nend\n\ngroup :test do\n gem 'fakeweb'\nend/ + assert_file "Gemfile", /\n\ngroup :development, :test do\n gem 'rspec-rails'\nend\n\ngroup :test do\n gem 'fakeweb'\nend\n\z/ end def test_github_should_create_an_indented_block @@ -153,7 +165,7 @@ class ActionsTest < Rails::Generators::TestCase gem "baz" end - assert_file "Gemfile", /\ngithub 'user\/repo' do\n gem 'foo'\n gem 'bar'\n gem 'baz'\nend/ + assert_file "Gemfile", /\n\ngithub 'user\/repo' do\n gem 'foo'\n gem 'bar'\n gem 'baz'\nend\n\z/ end def test_github_should_create_an_indented_block_with_options @@ -165,7 +177,7 @@ class ActionsTest < Rails::Generators::TestCase gem "baz" end - assert_file "Gemfile", /\ngithub 'user\/repo', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\nend/ + assert_file "Gemfile", /\n\ngithub 'user\/repo', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\nend\n\z/ end def test_github_should_create_an_indented_block_within_a_group @@ -177,9 +189,73 @@ class ActionsTest < Rails::Generators::TestCase gem "bar" gem "baz" end + github "user/repo2", a: "correct", other: true do + gem "foo" + gem "bar" + gem "baz" + end + end + + assert_file "Gemfile", /\n\ngroup :magic do\n github 'user\/repo', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\n end\n github 'user\/repo2', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\n end\nend\n\z/ + end + + def test_github_should_create_newline_between_blocks + run_generator + + action :github, "user/repo", a: "correct", other: true do + gem "foo" + gem "bar" + gem "baz" + end + + action :github, "user/repo2", a: "correct", other: true do + gem "foo" + gem "bar" + gem "baz" + end + + assert_file "Gemfile", /\n\ngithub 'user\/repo', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\nend\n\ngithub 'user\/repo2', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\nend\n\z/ + end + + def test_gem_with_gemfile_without_newline_at_the_end + run_generator + File.open("Gemfile", "a") { |f| f.write("gem 'rspec-rails'") } + + action :gem, "will-paginate" + assert_file "Gemfile", /gem 'rspec-rails'\ngem 'will-paginate'\n\z/ + end + + def test_gem_group_with_gemfile_without_newline_at_the_end + run_generator + File.open("Gemfile", "a") { |f| f.write("gem 'rspec-rails'") } + + action :gem_group, :test do + gem "fakeweb" end - assert_file "Gemfile", /\ngroup :magic do\n github 'user\/repo', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\n end\nend\n/ + assert_file "Gemfile", /gem 'rspec-rails'\n\ngroup :test do\n gem 'fakeweb'\nend\n\z/ + end + + def test_add_source_with_gemfile_without_newline_at_the_end + run_generator + File.open("Gemfile", "a") { |f| f.write("gem 'rspec-rails'") } + + action :add_source, "http://gems.github.com" do + gem "fakeweb" + end + + assert_file "Gemfile", /gem 'rspec-rails'\n\nsource 'http:\/\/gems\.github\.com' do\n gem 'fakeweb'\nend\n\z/ + end + + def test_github_with_gemfile_without_newline_at_the_end + run_generator + File.open("Gemfile", "a") { |f| f.write("gem 'rspec-rails'") } + + action :github, "user/repo" do + gem "fakeweb" + end + + assert_file "Gemfile", /gem 'rspec-rails'\n\ngithub 'user\/repo' do\n gem 'fakeweb'\nend\n\z/ end def test_environment_should_include_data_in_environment_initializer_block @@ -505,7 +581,6 @@ F end private - def action(*args, &block) capture(:stdout) { generator.send(*args, &block) } end diff --git a/railties/test/generators/api_app_generator_test.rb b/railties/test/generators/api_app_generator_test.rb index d03178da66..099bad8fb9 100644 --- a/railties/test/generators/api_app_generator_test.rb +++ b/railties/test/generators/api_app_generator_test.rb @@ -109,7 +109,6 @@ class ApiAppGeneratorTest < Rails::Generators::TestCase end private - def default_files %w(.gitignore .ruby-version diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 5b439fdcba..43461036f3 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -678,7 +678,7 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_inclusion_of_listen_related_configuration_by_default run_generator - if RbConfig::CONFIG["host_os"] =~ /darwin|linux/ + if /darwin|linux/.match?(RbConfig::CONFIG["host_os"]) assert_listen_related_configuration else assert_no_listen_related_configuration @@ -690,7 +690,7 @@ class AppGeneratorTest < Rails::Generators::TestCase Object.const_set(:RUBY_ENGINE, "MyRuby") run_generator - if RbConfig::CONFIG["host_os"] =~ /darwin|linux/ + if /darwin|linux/.match?(RbConfig::CONFIG["host_os"]) assert_listen_related_configuration else assert_no_listen_related_configuration @@ -708,7 +708,7 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_evented_file_update_checker_config run_generator assert_file "config/environments/development.rb" do |content| - if RbConfig::CONFIG["host_os"] =~ /darwin|linux/ + if /darwin|linux/.match?(RbConfig::CONFIG["host_os"]) assert_match(/^\s*config\.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content) else assert_match(/^\s*# config\.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content) diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb index e6b614a935..080e54a1ca 100644 --- a/railties/test/generators/migration_generator_test.rb +++ b/railties/test/generators/migration_generator_test.rb @@ -270,6 +270,21 @@ class MigrationGeneratorTest < Rails::Generators::TestCase end end + def test_create_table_migration_with_timestamps + run_generator ["create_books", "title:string", "content:text"] + assert_migration "db/migrate/create_books.rb", /t.timestamps/ + end + + def test_create_table_timestamps_are_skipped + run_generator ["create_books", "title:string", "content:text", "--no-timestamps"] + + assert_migration "db/migrate/create_books.rb" do |m| + assert_method :change, m do |change| + assert_no_match(/t.timestamps/, change) + end + end + end + def test_add_uuid_to_create_table_migration run_generator ["create_books", "--primary_key_type=uuid"] assert_migration "db/migrate/create_books.rb" do |content| @@ -430,7 +445,6 @@ class MigrationGeneratorTest < Rails::Generators::TestCase end private - def with_singular_table_name old_state = ActiveRecord::Base.pluralize_table_names ActiveRecord::Base.pluralize_table_names = false diff --git a/railties/test/generators/named_base_test.rb b/railties/test/generators/named_base_test.rb index 4e61b660d7..1b45c58b0e 100644 --- a/railties/test/generators/named_base_test.rb +++ b/railties/test/generators/named_base_test.rb @@ -169,7 +169,6 @@ class NamedBaseTest < Rails::Generators::TestCase end private - def assert_name(generator, value, method) assert_equal value, generator.send(method) end diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb index f45464f8d0..db774f6ac1 100644 --- a/railties/test/generators/plugin_generator_test.rb +++ b/railties/test/generators/plugin_generator_test.rb @@ -713,7 +713,6 @@ class PluginGeneratorTest < Rails::Generators::TestCase end private - def action(*args, &block) silence(:stdout) { generator.send(*args, &block) } end diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index fab704944b..6077ba3ee7 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -301,7 +301,7 @@ module TestHelpers # stderr:: true to pass STDERR output straight to the "real" STDERR. # By default, the STDERR and STDOUT of the process will be # combined in the returned string. - def rails(*args, allow_failure: false, stderr: false) + def rails(*args, allow_failure: false, stderr: false, stdin: File::NULL) args = args.flatten fork = true @@ -328,7 +328,7 @@ module TestHelpers out_read.close err_read.close if err_read - $stdin.reopen(File::NULL, "r") + $stdin.reopen(stdin, "r") $stdout.reopen(out_write) $stderr.reopen(err_write) @@ -448,18 +448,36 @@ module TestHelpers $:.reject! { |path| path =~ %r'/(#{to_remove.join('|')})/' } end - def use_postgresql - File.open("#{app_path}/config/database.yml", "w") do |f| - f.puts <<-YAML - default: &default - adapter: postgresql - pool: 5 - database: railties_test - development: - <<: *default - test: - <<: *default - YAML + def use_postgresql(multi_db: false) + if multi_db + File.open("#{app_path}/config/database.yml", "w") do |f| + f.puts <<-YAML + default: &default + adapter: postgresql + pool: 5 + development: + primary: + <<: *default + database: railties_test + animals: + <<: *default + database: railties_animals_test + migrations_paths: db/animals_migrate + YAML + end + else + File.open("#{app_path}/config/database.yml", "w") do |f| + f.puts <<-YAML + default: &default + adapter: postgresql + pool: 5 + database: railties_test + development: + <<: *default + test: + <<: *default + YAML + end end end end diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 8ce68dbcfa..06836844f0 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -34,7 +34,7 @@ module RailtiesTest def migrations migration_root = File.expand_path(ActiveRecord::Migrator.migrations_paths.first, app_path) - ActiveRecord::MigrationContext.new(migration_root).migrations + ActiveRecord::MigrationContext.new(migration_root, ActiveRecord::SchemaMigration).migrations end test "serving sprocket's assets" do @@ -110,7 +110,7 @@ module RailtiesTest assert_no_match(/\d+_create_users/, output.join("\n")) - bukkits_migration_order = output.index(output.detect { |o| /NOTE: Migration \d+_create_sessions\.rb from bukkits has been skipped/ =~ o }) + bukkits_migration_order = output.index(output.detect { |o| /NOTE: Migration \d+_create_sessions\.rb from bukkits has been skipped/.match?(o) }) assert_not_nil bukkits_migration_order, "Expected migration to be skipped" end end |