aboutsummaryrefslogtreecommitdiffstats
path: root/railties/test/application
diff options
context:
space:
mode:
Diffstat (limited to 'railties/test/application')
-rw-r--r--railties/test/application/asset_debugging_test.rb123
-rw-r--r--railties/test/application/assets_test.rb119
-rw-r--r--railties/test/application/bin_setup_test.rb34
-rw-r--r--railties/test/application/configuration/custom_test.rb27
-rw-r--r--railties/test/application/configuration_test.rb1651
-rw-r--r--railties/test/application/console_test.rb97
-rw-r--r--railties/test/application/content_security_policy_test.rb223
-rw-r--r--railties/test/application/credentials_test.rb56
-rw-r--r--railties/test/application/current_attributes_integration_test.rb88
-rw-r--r--railties/test/application/dbconsole_test.rb74
-rw-r--r--railties/test/application/generators_test.rb44
-rw-r--r--railties/test/application/help_test.rb25
-rw-r--r--railties/test/application/initializers/frameworks_test.rb97
-rw-r--r--railties/test/application/initializers/hooks_test.rb9
-rw-r--r--railties/test/application/initializers/i18n_test.rb37
-rw-r--r--railties/test/application/initializers/load_path_test.rb7
-rw-r--r--railties/test/application/initializers/notifications_test.rb12
-rw-r--r--railties/test/application/integration_test_case_test.rb44
-rw-r--r--railties/test/application/loading_test.rb177
-rw-r--r--railties/test/application/mailer_previews_test.rb317
-rw-r--r--railties/test/application/middleware/cache_test.rb41
-rw-r--r--railties/test/application/middleware/cookies_test.rb168
-rw-r--r--railties/test/application/middleware/exceptions_test.rb35
-rw-r--r--railties/test/application/middleware/remote_ip_test.rb16
-rw-r--r--railties/test/application/middleware/sendfile_test.rb15
-rw-r--r--railties/test/application/middleware/session_test.rb236
-rw-r--r--railties/test/application/middleware/static_test.rb28
-rw-r--r--railties/test/application/middleware_test.rb113
-rw-r--r--railties/test/application/multiple_applications_test.rb41
-rw-r--r--railties/test/application/paths_test.rb11
-rw-r--r--railties/test/application/per_request_digest_cache_test.rb32
-rw-r--r--railties/test/application/rack/logger_test.rb12
-rw-r--r--railties/test/application/rackup_test.rb7
-rw-r--r--railties/test/application/rake/dbs_test.rb519
-rw-r--r--railties/test/application/rake/dev_test.rb50
-rw-r--r--railties/test/application/rake/framework_test.rb14
-rw-r--r--railties/test/application/rake/initializers_test.rb44
-rw-r--r--railties/test/application/rake/log_test.rb35
-rw-r--r--railties/test/application/rake/migrations_test.rb493
-rw-r--r--railties/test/application/rake/multi_dbs_test.rb251
-rw-r--r--railties/test/application/rake/notes_test.rb149
-rw-r--r--railties/test/application/rake/restart_test.rb26
-rw-r--r--railties/test/application/rake/routes_test.rb59
-rw-r--r--railties/test/application/rake/tmp_test.rb43
-rw-r--r--railties/test/application/rake_test.rb287
-rw-r--r--railties/test/application/rendering_test.rb19
-rw-r--r--railties/test/application/routing_test.rb415
-rw-r--r--railties/test/application/runner_test.rb87
-rw-r--r--railties/test/application/server_test.rb52
-rw-r--r--railties/test/application/test_runner_test.rb693
-rw-r--r--railties/test/application/test_test.rb130
-rw-r--r--railties/test/application/url_generation_test.rb15
-rw-r--r--railties/test/application/version_test.rb26
-rw-r--r--railties/test/application/zeitwerk_integration_test.rb304
54 files changed, 5834 insertions, 1893 deletions
diff --git a/railties/test/application/asset_debugging_test.rb b/railties/test/application/asset_debugging_test.rb
index bcb6aff0d7..7623e8e352 100644
--- a/railties/test/application/asset_debugging_test.rb
+++ b/railties/test/application/asset_debugging_test.rb
@@ -1,5 +1,7 @@
-require 'isolation/abstract_unit'
-require 'rack/test'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "rack/test"
module ApplicationTests
class AssetDebuggingTest < ActiveSupport::TestCase
@@ -7,10 +9,7 @@ module ApplicationTests
include Rack::Test::Methods
def setup
- # FIXME: shush Sass warning spam, not relevant to testing Railties
- Kernel.silence_warnings do
- build_app(initializers: true)
- end
+ build_app(initializers: true)
app_file "app/assets/javascripts/application.js", "//= require_tree ."
app_file "app/assets/javascripts/xmlhr.js", "function f1() { alert(); }"
@@ -28,24 +27,16 @@ module ApplicationTests
RUBY
ENV["RAILS_ENV"] = "production"
-
- boot_rails
end
def teardown
teardown_app
end
- # FIXME: shush Sass warning spam, not relevant to testing Railties
- def get(*)
- Kernel.silence_warnings { super }
- end
-
test "assets are concatenated when debug is off and compile is off either if debug_assets param is provided" do
# config.assets.debug and config.assets.compile are false for production environment
ENV["RAILS_ENV"] = "production"
- output = Dir.chdir(app_path){ `bin/rails assets:precompile --trace 2>&1` }
- assert $?.success?, output
+ rails "assets:precompile", "--trace"
# Load app env
app "production"
@@ -53,7 +44,7 @@ module ApplicationTests
class ::PostsController < ActionController::Base ; end
# the debug_assets params isn't used if compile is off
- get '/posts?debug_assets=true'
+ get "/posts?debug_assets=true"
assert_match(/<script src="\/assets\/application-([0-z]+)\.js"><\/script>/, last_response.body)
assert_no_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js"><\/script>/, last_response.body)
end
@@ -66,9 +57,107 @@ module ApplicationTests
class ::PostsController < ActionController::Base ; end
- get '/posts?debug_assets=true'
+ get "/posts?debug_assets=true"
assert_match(/<script src="\/assets\/application(\.self)?-([0-z]+)\.js\?body=1"><\/script>/, last_response.body)
assert_match(/<script src="\/assets\/xmlhr(\.self)?-([0-z]+)\.js\?body=1"><\/script>/, last_response.body)
end
+
+ test "public path and tag methods are not over-written by the asset pipeline" do
+ contents = "doesnotexist"
+ cases = {
+ asset_path: %r{/#{contents}},
+ image_path: %r{/images/#{contents}},
+ video_path: %r{/videos/#{contents}},
+ audio_path: %r{/audios/#{contents}},
+ font_path: %r{/fonts/#{contents}},
+ javascript_path: %r{/javascripts/#{contents}},
+ stylesheet_path: %r{/stylesheets/#{contents}},
+ image_tag: %r{<img src="/images/#{contents}"},
+ favicon_link_tag: %r{<link rel="shortcut icon" type="image/x-icon" href="/images/#{contents}" />},
+ stylesheet_link_tag: %r{<link rel="stylesheet" media="screen" href="/stylesheets/#{contents}.css" />},
+ javascript_include_tag: %r{<script src="/javascripts/#{contents}.js">},
+ audio_tag: %r{<audio src="/audios/#{contents}"></audio>},
+ video_tag: %r{<video src="/videos/#{contents}"></video>},
+ image_submit_tag: %r{<input type="image" src="/images/#{contents}" />}
+ }
+
+ cases.each do |(view_method, tag_match)|
+ app_file "app/views/posts/index.html.erb", "<%= #{view_method} '#{contents}', skip_pipeline: true %>"
+
+ app "development"
+
+ class ::PostsController < ActionController::Base ; end
+
+ get "/posts?debug_assets=true"
+
+ body = last_response.body
+ assert_match(tag_match, body, "Expected `#{view_method}` to produce a match to #{tag_match}, but did not: #{body}")
+ end
+ end
+
+ test "public URL methods are not over-written by the asset pipeline" do
+ contents = "doesnotexist"
+ cases = {
+ asset_url: %r{http://example.org/#{contents}},
+ image_url: %r{http://example.org/images/#{contents}},
+ video_url: %r{http://example.org/videos/#{contents}},
+ audio_url: %r{http://example.org/audios/#{contents}},
+ font_url: %r{http://example.org/fonts/#{contents}},
+ javascript_url: %r{http://example.org/javascripts/#{contents}},
+ stylesheet_url: %r{http://example.org/stylesheets/#{contents}},
+ }
+
+ cases.each do |(view_method, tag_match)|
+ app_file "app/views/posts/index.html.erb", "<%= #{view_method} '#{contents}', skip_pipeline: true %>"
+
+ app "development"
+
+ class ::PostsController < ActionController::Base ; end
+
+ get "/posts?debug_assets=true"
+
+ body = last_response.body
+ assert_match(tag_match, body, "Expected `#{view_method}` to produce a match to #{tag_match}, but did not: #{body}")
+ end
+ end
+
+ test "{ skip_pipeline: true } does not use the asset pipeline" do
+ cases = {
+ /\/assets\/application-.*.\.js/ => {},
+ /application.js/ => { skip_pipeline: true },
+ }
+ cases.each do |(tag_match, options_hash)|
+ app_file "app/views/posts/index.html.erb", "<%= asset_path('application.js', #{options_hash}) %>"
+
+ app "development"
+
+ class ::PostsController < ActionController::Base ; end
+
+ get "/posts?debug_assets=true"
+
+ body = last_response.body.strip
+ assert_match(tag_match, body, "Expected `asset_path` with `#{options_hash}` to produce a match to #{tag_match}, but did not: #{body}")
+ end
+ end
+
+ test "public_compute_asset_path does not use the asset pipeline" do
+ cases = {
+ compute_asset_path: /\/assets\/application-.*.\.js/,
+ public_compute_asset_path: /application.js/,
+ }
+
+ cases.each do |(view_method, tag_match)|
+ app_file "app/views/posts/index.html.erb", "<%= #{ view_method } 'application.js' %>"
+
+ app "development"
+
+ class ::PostsController < ActionController::Base ; end
+
+ get "/posts?debug_assets=true"
+
+ body = last_response.body.strip
+ assert_match(tag_match, body, "Expected `#{view_method}` to produce a match to #{ tag_match }, but did not: #{ body }")
+ end
+ end
end
end
diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb
index 11e19eec80..a80581211b 100644
--- a/railties/test/application/assets_test.rb
+++ b/railties/test/application/assets_test.rb
@@ -1,6 +1,8 @@
-require 'isolation/abstract_unit'
-require 'rack/test'
-require 'active_support/json'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "rack/test"
+require "active_support/json"
module ApplicationTests
class AssetsTest < ActiveSupport::TestCase
@@ -9,7 +11,6 @@ module ApplicationTests
def setup
build_app(initializers: true)
- boot_rails
end
def teardown
@@ -36,7 +37,7 @@ module ApplicationTests
def clean_assets!
quietly do
- assert Dir.chdir(app_path) { system('bin/rails assets:clobber') }
+ assert Dir.chdir(app_path) { system("bin/rails assets:clobber") }
end
end
@@ -46,14 +47,14 @@ module ApplicationTests
end
def assert_no_file_exists(filename)
- assert !File.exist?(filename), "#{filename} does exist"
+ assert_not File.exist?(filename), "#{filename} does exist"
end
test "assets routes have higher priority" do
app_file "app/assets/images/rails.png", "notactuallyapng"
app_file "app/assets/javascripts/demo.js.erb", "a = <%= image_path('rails.png').inspect %>;"
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get '*path', to: lambda { |env| [200, { "Content-Type" => "text/html" }, ["Not an asset"]] }
end
@@ -61,29 +62,12 @@ module ApplicationTests
add_to_env_config "development", "config.assets.digest = false"
- # FIXME: shush Sass warning spam, not relevant to testing Railties
- Kernel.silence_warnings do
- require "#{app_path}/config/environment"
- end
+ require "#{app_path}/config/environment"
get "/assets/demo.js"
assert_equal 'a = "/assets/rails.png";', last_response.body.strip
end
- test "assets do not require compressors until it is used" do
- app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();"
- add_to_env_config "production", "config.assets.compile = true"
- add_to_env_config "production", "config.assets.precompile = []"
-
- # Load app env
- app "production"
-
- assert !defined?(Uglifier)
- get "/assets/demo.js"
- assert_match "alert()", last_response.body
- assert defined?(Uglifier)
- end
-
test "precompile creates the file, gives it the original asset's content and run in production as default" do
app_file "app/assets/config/manifest.js", "//= link_tree ../javascripts"
app_file "app/assets/javascripts/application.js", "alert();"
@@ -111,8 +95,8 @@ module ApplicationTests
eoruby
precompile! \
- RAILS_ENV: 'production',
- DATABASE_URL: 'postgresql://baduser:badpass@127.0.0.1/dbname'
+ RAILS_ENV: "production",
+ DATABASE_URL: "postgresql://baduser:badpass@127.0.0.1/dbname"
files = Dir["#{app_path}/public/assets/application-*.js"]
files << Dir["#{app_path}/public/assets/foo/application-*.js"].first
@@ -177,19 +161,19 @@ module ApplicationTests
assert_file_exists("#{app_path}/public/assets/something/index-*.js")
end
- test 'precompile use assets defined in app env config' do
- add_to_env_config 'production', 'config.assets.precompile = [ "something.js" ]'
- app_file 'app/assets/javascripts/something.js.erb', 'alert();'
+ test "precompile use assets defined in app env config" do
+ add_to_env_config "production", 'config.assets.precompile = [ "something.js" ]'
+ app_file "app/assets/javascripts/something.js.erb", "alert();"
- precompile! RAILS_ENV: 'production'
+ precompile! RAILS_ENV: "production"
assert_file_exists("#{app_path}/public/assets/something-*.js")
end
- test 'sprockets cache is not shared between environments' do
+ test "sprockets cache is not shared between environments" do
app_file "app/assets/images/rails.png", "notactuallyapng"
- app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
- add_to_env_config 'production', 'config.assets.prefix = "production_assets"'
+ app_file "app/assets/stylesheets/application.css.erb", "body { background: '<%= asset_path('rails.png') %>'; }"
+ add_to_env_config "production", 'config.assets.prefix = "production_assets"'
precompile!
@@ -198,7 +182,7 @@ module ApplicationTests
file = Dir["#{app_path}/public/assets/application-*.css"].first
assert_match(/assets\/rails-([0-z]+)\.png/, File.read(file))
- precompile! RAILS_ENV: 'production'
+ precompile! RAILS_ENV: "production"
assert_file_exists("#{app_path}/public/production_assets/application-*.css")
@@ -206,17 +190,17 @@ module ApplicationTests
assert_match(/production_assets\/rails-([0-z]+)\.png/, File.read(file))
end
- test 'precompile use assets defined in app config and reassigned in app env config' do
+ test "precompile use assets defined in app config and reassigned in app env config" do
add_to_config 'config.assets.precompile = [ "something_manifest.js" ]'
- add_to_env_config 'production', 'config.assets.precompile += [ "another_manifest.js" ]'
+ add_to_env_config "production", 'config.assets.precompile += [ "another_manifest.js" ]'
- app_file 'app/assets/config/something_manifest.js', '//= link something.js'
- app_file 'app/assets/config/another_manifest.js', '//= link another.js'
+ app_file "app/assets/config/something_manifest.js", "//= link something.js"
+ app_file "app/assets/config/another_manifest.js", "//= link another.js"
- app_file 'app/assets/javascripts/something.js.erb', 'alert();'
- app_file 'app/assets/javascripts/another.js.erb', 'alert();'
+ app_file "app/assets/javascripts/something.js.erb", "alert();"
+ app_file "app/assets/javascripts/another.js.erb", "alert();"
- precompile! RAILS_ENV: 'production'
+ precompile! RAILS_ENV: "production"
assert_file_exists("#{app_path}/public/assets/something_manifest-*.js")
assert_file_exists("#{app_path}/public/assets/something-*.js")
@@ -262,7 +246,7 @@ module ApplicationTests
app_file "app/assets/javascripts/application.js", "alert();"
add_to_env_config "production", "config.public_file_server.enabled = true"
- precompile! RAILS_ENV: 'production'
+ precompile! RAILS_ENV: "production"
manifest = Dir["#{app_path}/public/assets/.sprockets-manifest-*.json"].first
assets = ActiveSupport::JSON.decode(File.read(manifest))
@@ -272,10 +256,10 @@ module ApplicationTests
app "production"
# Checking if Uglifier is defined we can know if Sprockets was reached or not
- assert !defined?(Uglifier)
+ assert_not defined?(Uglifier)
get "/assets/#{asset_path}"
assert_match "alert()", last_response.body
- assert !defined?(Uglifier)
+ assert_not defined?(Uglifier)
end
test "precompile properly refers files referenced with asset_path" do
@@ -293,7 +277,7 @@ module ApplicationTests
app_file "app/assets/stylesheets/application.css.erb", "p { background-image: url(<%= asset_path('rails.png') %>) }"
- precompile! RAILS_ENV: 'production'
+ precompile! RAILS_ENV: "production"
manifest = Dir["#{app_path}/public/assets/.sprockets-manifest-*.json"].first
assets = ActiveSupport::JSON.decode(File.read(manifest))
@@ -307,11 +291,11 @@ module ApplicationTests
assert_not_equal asset_path, assets["assets"]["application.css"]
end
- test "precompile appends the md5 hash to files referenced with asset_path and run in production with digest true" do
+ test "precompile appends the MD5 hash to files referenced with asset_path and run in production with digest true" do
app_file "app/assets/images/rails.png", "notactuallyapng"
app_file "app/assets/stylesheets/application.css.erb", "p { background-image: url(<%= asset_path('rails.png') %>) }"
- precompile! RAILS_ENV: 'production'
+ precompile! RAILS_ENV: "production"
file = Dir["#{app_path}/public/assets/application-*.css"].first
assert_match(/\/assets\/rails-([0-z]+)\.png/, File.read(file))
@@ -344,8 +328,7 @@ module ApplicationTests
clean_assets!
- files = Dir["#{app_path}/public/assets/**/*", "#{app_path}/tmp/cache/assets/development/*",
- "#{app_path}/tmp/cache/assets/test/*", "#{app_path}/tmp/cache/assets/production/*"]
+ files = Dir["#{app_path}/public/assets/**/*"]
assert_equal 0, files.length, "Expected no assets, but found #{files.join(', ')}"
end
@@ -377,16 +360,16 @@ module ApplicationTests
class ::OmgController < ActionController::Base
def index
flash[:cool_story] = true
- render text: "ok"
+ render plain: "ok"
end
end
get "/omg"
- assert_equal 'ok', last_response.body
+ assert_equal "ok", last_response.body
get "/assets/demo.js"
assert_match "alert()", last_response.body
- assert_equal nil, last_response.headers["Set-Cookie"]
+ assert_nil last_response.headers["Set-Cookie"]
end
test "files in any assets/ directories are not added to Sprockets" do
@@ -410,7 +393,7 @@ module ApplicationTests
app_with_assets_in_view
# config.assets.debug and config.assets.compile are false for production environment
- precompile! RAILS_ENV: 'production'
+ precompile! RAILS_ENV: "production"
# Load app env
app "production"
@@ -418,7 +401,7 @@ module ApplicationTests
class ::PostsController < ActionController::Base ; end
# the debug_assets params isn't used if compile is off
- get '/posts?debug_assets=true'
+ get "/posts?debug_assets=true"
assert_match(/<script src="\/assets\/application-([0-z]+)\.js"><\/script>/, last_response.body)
assert_no_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js"><\/script>/, last_response.body)
end
@@ -446,13 +429,13 @@ module ApplicationTests
end
test "digested assets are not mistakenly removed" do
- app_file "app/assets/application.js", "alert();"
+ app_file "app/assets/application.css", "div { font-weight: bold }"
add_to_config "config.assets.compile = true"
precompile!
- files = Dir["#{app_path}/public/assets/application-*.js"]
- assert_equal 1, files.length, "Expected digested application.js asset to be generated, but none found"
+ files = Dir["#{app_path}/public/assets/application-*.css"]
+ assert_equal 1, files.length, "Expected digested application.css asset to be generated, but none found"
end
test "digested assets are removed from configured path" do
@@ -467,7 +450,7 @@ module ApplicationTests
assert_equal 0, files.length, "Expected application.js asset to be removed, but still exists"
end
- test "asset urls should use the request's protocol by default" do
+ test "asset URLs should use the request's protocol by default" do
app_with_assets_in_view
add_to_config "config.asset_host = 'example.com'"
add_to_env_config "development", "config.assets.digest = false"
@@ -477,13 +460,13 @@ module ApplicationTests
class ::PostsController < ActionController::Base; end
- get '/posts', {}, {'HTTPS'=>'off'}
+ get "/posts", {}, { "HTTPS" => "off" }
assert_match('src="http://example.com/assets/application.self.js', last_response.body)
- get '/posts', {}, {'HTTPS'=>'on'}
+ get "/posts", {}, { "HTTPS" => "on" }
assert_match('src="https://example.com/assets/application.self.js', last_response.body)
end
- test "asset urls should be protocol-relative if no request is in scope" do
+ test "asset URLs should be protocol-relative if no request is in scope" do
app_file "app/assets/images/rails.png", "notreallyapng"
app_file "app/assets/javascripts/image_loader.js.erb", "var src='<%= image_path('rails.png') %>';"
add_to_config "config.assets.precompile = %w{rails.png image_loader.js}"
@@ -509,16 +492,16 @@ module ApplicationTests
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(); }"
- app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'application' %>"
+ 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(); }"
+ app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'application' %>"
- app_file "config/routes.rb", <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get '/posts', :to => "posts#index"
end
RUBY
- end
+ end
end
end
diff --git a/railties/test/application/bin_setup_test.rb b/railties/test/application/bin_setup_test.rb
index a07c51a60f..a952d2466b 100644
--- a/railties/test/application/bin_setup_test.rb
+++ b/railties/test/application/bin_setup_test.rb
@@ -1,4 +1,6 @@
-require 'isolation/abstract_unit'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
module ApplicationTests
class BinSetupTest < ActiveSupport::TestCase
@@ -14,16 +16,16 @@ module ApplicationTests
def test_bin_setup
Dir.chdir(app_path) do
- app_file 'db/schema.rb', <<-RUBY
+ app_file "db/schema.rb", <<-RUBY
ActiveRecord::Schema.define(version: 20140423102712) do
create_table(:articles) {}
end
RUBY
- list_tables = lambda { `bin/rails runner 'p ActiveRecord::Base.connection.tables'`.strip }
+ list_tables = lambda { rails("runner", "p ActiveRecord::Base.connection.tables").strip }
File.write("log/test.log", "zomg!")
- assert_equal '[]', list_tables.call
+ assert_equal "[]", list_tables.call
assert_equal 5, File.size("log/test.log")
assert_not File.exist?("tmp/restart.txt")
`bin/setup 2>&1`
@@ -35,18 +37,28 @@ module ApplicationTests
def test_bin_setup_output
Dir.chdir(app_path) do
- app_file 'db/schema.rb', ""
+ app_file "db/schema.rb", ""
output = `bin/setup 2>&1`
- assert_equal(<<-OUTPUT, output)
-== Installing dependencies ==
-The Gemfile's dependencies are satisfied
-== Preparing database ==
+ # Ignore line that's only output by Bundler < 1.14
+ 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 ==
+ The Gemfile's dependencies are satisfied
+
+ == Preparing database ==
+ Created database 'db/development.sqlite3'
+ Created database 'db/test.sqlite3'
-== Removing old logs and tempfiles ==
+ == Removing old logs and tempfiles ==
-== Restarting application server ==
+ == Restarting application server ==
OUTPUT
end
end
diff --git a/railties/test/application/configuration/custom_test.rb b/railties/test/application/configuration/custom_test.rb
index 28b3b2f2d6..608bc2fbe3 100644
--- a/railties/test/application/configuration/custom_test.rb
+++ b/railties/test/application/configuration/custom_test.rb
@@ -1,20 +1,20 @@
-require 'isolation/abstract_unit'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
module ApplicationTests
module ConfigurationTests
class CustomTest < ActiveSupport::TestCase
def setup
build_app
- boot_rails
FileUtils.rm_rf("#{app_path}/config/environments")
end
def teardown
teardown_app
- FileUtils.rm_rf(new_app) if File.directory?(new_app)
end
- test 'access custom configuration point' do
+ test "access custom configuration point" do
add_to_config <<-RUBY
config.x.payment_processing.schedule = :daily
config.x.payment_processing.retries = 3
@@ -29,23 +29,16 @@ module ApplicationTests
assert_equal 3, x.payment_processing.retries
assert_equal true, x.super_debugger
assert_equal false, x.hyper_debugger
- assert_equal nil, x.nil_debugger
+ assert_nil x.nil_debugger
assert_nil x.i_do_not_exist.zomg
+
+ # test that custom configuration responds to all messages
+ assert_respond_to x, :i_do_not_exist
+ assert_kind_of Method, x.method(:i_do_not_exist)
+ assert_kind_of ActiveSupport::OrderedOptions, x.i_do_not_exist
end
private
- def new_app
- File.expand_path("#{app_path}/../new_app")
- end
-
- def copy_app
- FileUtils.cp_r(app_path, new_app)
- end
-
- def app
- @app ||= Rails.application
- end
-
def require_environment
require "#{app_path}/config/environment"
end
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index decc4d138d..b8e167b488 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -1,6 +1,9 @@
+# frozen_string_literal: true
+
require "isolation/abstract_unit"
-require 'rack/test'
-require 'env_helpers'
+require "rack/test"
+require "env_helpers"
+require "set"
class ::MyMailInterceptor
def self.delivering_email(email); email; end
@@ -34,25 +37,21 @@ module ApplicationTests
FileUtils.cp_r(app_path, new_app)
end
- def app(env = 'development')
+ def app(env = "development")
@app ||= begin
- ENV['RAILS_ENV'] = env
+ ENV["RAILS_ENV"] = env
- # FIXME: shush Sass warning spam, not relevant to testing Railties
- Kernel.silence_warnings do
- require "#{app_path}/config/environment"
- end
+ require "#{app_path}/config/environment"
Rails.application
ensure
- ENV.delete 'RAILS_ENV'
+ ENV.delete "RAILS_ENV"
end
end
def setup
build_app
- boot_rails
- supress_default_config
+ suppress_default_config
end
def teardown
@@ -60,7 +59,7 @@ module ApplicationTests
FileUtils.rm_rf(new_app) if File.directory?(new_app)
end
- def supress_default_config
+ def suppress_default_config
FileUtils.mv("#{app_path}/config/environments", "#{app_path}/config/__environments__")
end
@@ -75,7 +74,19 @@ module ApplicationTests
switch_env "RAILS_ENV", nil do
Rails.env = "development"
assert_equal "development", Rails.env
- assert_nil ENV['RAILS_ENV']
+ assert_nil ENV["RAILS_ENV"]
+ end
+ end
+
+ test "Rails.env falls back to development if RAILS_ENV is blank and RACK_ENV is nil" do
+ with_rails_env("") do
+ assert_equal "development", Rails.env
+ end
+ end
+
+ test "Rails.env falls back to development if RACK_ENV is blank and RAILS_ENV is nil" do
+ with_rack_env("") do
+ assert_equal "development", Rails.env
end
end
@@ -83,8 +94,8 @@ module ApplicationTests
restore_default_config
with_rails_env "development" do
- app 'development'
- assert Rails.application.config.log_tags.blank?
+ app "development"
+ assert_predicate Rails.application.config.log_tags, :blank?
end
end
@@ -92,13 +103,13 @@ module ApplicationTests
restore_default_config
with_rails_env "production" do
- app 'production'
+ app "production"
assert_equal [:request_id], Rails.application.config.log_tags
end
end
test "lib dir is on LOAD_PATH during config" do
- app_file 'lib/my_logger.rb', <<-RUBY
+ app_file "lib/my_logger.rb", <<-RUBY
require "logger"
class MyLogger < ::Logger
end
@@ -108,9 +119,21 @@ module ApplicationTests
config.logger = MyLogger.new STDOUT
RUBY
- app 'development'
+ app "development"
- assert_equal 'MyLogger', Rails.application.config.logger.class.name
+ assert_equal "MyLogger", Rails.application.config.logger.class.name
+ end
+
+ test "raises an error if cache does not support recyclable cache keys" do
+ build_app(initializers: true)
+ add_to_env_config "production", "config.cache_store = Class.new {}.new"
+ add_to_env_config "production", "config.active_record.cache_versioning = true"
+
+ error = assert_raise(RuntimeError) do
+ app "production"
+ end
+
+ assert_match(/You're using a cache/, error.message)
end
test "a renders exception on pending migration" do
@@ -120,7 +143,7 @@ module ApplicationTests
config.action_dispatch.show_exceptions = true
RUBY
- app_file 'db/migrate/20140708012246_create_user.rb', <<-RUBY
+ app_file "db/migrate/20140708012246_create_user.rb", <<-RUBY
class CreateUser < ActiveRecord::Migration::Current
def change
create_table :users
@@ -128,7 +151,7 @@ module ApplicationTests
end
RUBY
- app 'development'
+ app "development"
ActiveRecord::Migrator.migrations_paths = ["#{app_path}/db/migrate"]
@@ -157,31 +180,29 @@ module ApplicationTests
end
test "Rails.application is nil until app is initialized" do
- require 'rails'
+ require "rails"
assert_nil Rails.application
- app 'development'
+ app "development"
assert_equal AppTemplate::Application.instance, Rails.application
end
test "Rails.application responds to all instance methods" do
- app 'development'
- assert_respond_to Rails.application, :routes_reloader
+ app "development"
assert_equal Rails.application.routes_reloader, AppTemplate::Application.routes_reloader
end
test "Rails::Application responds to paths" do
- app 'development'
- assert_respond_to AppTemplate::Application, :paths
+ app "development"
assert_equal ["#{app_path}/app/views"], AppTemplate::Application.paths["app/views"].expanded
end
test "the application root is set correctly" do
- app 'development'
+ app "development"
assert_equal Pathname.new(app_path), Rails.application.root
end
test "the application root can be seen from the application singleton" do
- app 'development'
+ app "development"
assert_equal Pathname.new(app_path), AppTemplate::Application.root
end
@@ -193,7 +214,7 @@ module ApplicationTests
use_frameworks []
- app 'development'
+ app "development"
assert_equal Pathname.new(new_app), Rails.application.root
end
@@ -204,7 +225,7 @@ module ApplicationTests
use_frameworks []
Dir.chdir("#{app_path}") do
- app 'development'
+ app "development"
assert_equal Pathname.new("#{app_path}"), Rails.application.root
end
end
@@ -214,7 +235,7 @@ module ApplicationTests
config.root = "#{app_path}"
RUBY
- app 'development'
+ app "development"
assert_instance_of Pathname, Rails.root
end
@@ -224,28 +245,198 @@ module ApplicationTests
config.paths["public"] = "somewhere"
RUBY
- app 'development'
+ app "development"
assert_instance_of Pathname, Rails.public_path
end
+ test "does not eager load controller actions in development" do
+ app_file "app/controllers/posts_controller.rb", <<-RUBY
+ class PostsController < ActionController::Base
+ def index;end
+ def show;end
+ end
+ RUBY
+
+ app "development"
+
+ assert_nil PostsController.instance_variable_get(:@action_methods)
+ end
+
+ test "eager loads controller actions in production" do
+ app_file "app/controllers/posts_controller.rb", <<-RUBY
+ class PostsController < ActionController::Base
+ def index;end
+ def show;end
+ end
+ RUBY
+
+ add_to_config <<-RUBY
+ config.eager_load = true
+ config.cache_classes = true
+ RUBY
+
+ app "production"
+
+ assert_equal %w(index show).to_set, PostsController.instance_variable_get(:@action_methods)
+ end
+
+ test "does not eager load mailer actions in development" do
+ app_file "app/mailers/posts_mailer.rb", <<-RUBY
+ class PostsMailer < ActionMailer::Base
+ def noop_email;end
+ end
+ RUBY
+
+ app "development"
+
+ assert_nil PostsMailer.instance_variable_get(:@action_methods)
+ end
+
+ test "eager loads mailer actions in production" do
+ app_file "app/mailers/posts_mailer.rb", <<-RUBY
+ class PostsMailer < ActionMailer::Base
+ def noop_email;end
+ end
+ RUBY
+
+ add_to_config <<-RUBY
+ config.eager_load = true
+ config.cache_classes = true
+ RUBY
+
+ app "production"
+
+ assert_equal %w(noop_email).to_set, PostsMailer.instance_variable_get(:@action_methods)
+ end
+
+ test "does not eager load attribute methods in development" 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
+
+ app "development"
+
+ assert_not_includes Post.instance_methods, :title
+ end
+
+ 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
+ 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 "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
config.cache_classes = true
RUBY
- app 'development'
+ app "development"
assert_equal :require, ActiveSupport::Dependencies.mechanism
end
test "application is always added to eager_load namespaces" do
- app 'development'
+ app "development"
assert_includes Rails.application.config.eager_load_namespaces, AppTemplate::Application
end
test "the application can be eager loaded even when there are no frameworks" do
+ FileUtils.rm_rf("#{app_path}/app/jobs/application_job.rb")
FileUtils.rm_rf("#{app_path}/app/models/application_record.rb")
FileUtils.rm_rf("#{app_path}/app/mailers/application_mailer.rb")
FileUtils.rm_rf("#{app_path}/config/environments")
@@ -257,7 +448,7 @@ module ApplicationTests
use_frameworks []
assert_nothing_raised do
- app 'development'
+ app "development"
end
end
@@ -269,18 +460,18 @@ module ApplicationTests
RUBY
assert_nothing_raised do
- app 'development'
+ app "development"
end
end
test "filter_parameters should be able to set via config.filter_parameters in an initializer" do
- app_file 'config/initializers/filter_parameters_logging.rb', <<-RUBY
+ app_file "config/initializers/filter_parameters_logging.rb", <<-RUBY
Rails.application.config.filter_parameters += [ :password, :foo, 'bar' ]
RUBY
- app 'development'
+ app "development"
- assert_equal [:password, :foo, 'bar'], Rails.application.env_config['action_dispatch.parameter_filter']
+ assert_equal [:password, :foo, "bar"], Rails.application.env_config["action_dispatch.parameter_filter"]
end
test "config.to_prepare is forwarded to ActionDispatch" do
@@ -292,9 +483,9 @@ module ApplicationTests
end
RUBY
- assert !$prepared
+ assert_not $prepared
- app 'development'
+ app "development"
get "/"
assert $prepared
@@ -306,7 +497,7 @@ module ApplicationTests
end
test "skipping config.encoding still results in 'utf-8' as the default" do
- app 'development'
+ app "development"
assert_utf8
end
@@ -315,7 +506,7 @@ module ApplicationTests
config.encoding = "utf-8"
RUBY
- app 'development'
+ app "development"
assert_utf8
end
@@ -324,7 +515,7 @@ module ApplicationTests
config.paths["public"] = "somewhere"
RUBY
- app 'development'
+ app "development"
assert_equal Pathname.new(app_path).join("somewhere"), Rails.public_path
end
@@ -332,7 +523,7 @@ module ApplicationTests
restore_default_config
with_rails_env "production" do
- app 'production'
+ app "production"
assert_not app.config.public_file_server.enabled
end
end
@@ -342,7 +533,7 @@ module ApplicationTests
with_rails_env "production" do
switch_env "RAILS_SERVE_STATIC_FILES", "1" do
- app 'production'
+ app "production"
assert app.config.public_file_server.enabled
end
end
@@ -353,7 +544,7 @@ module ApplicationTests
with_rails_env "production" do
switch_env "RAILS_LOG_TO_STDOUT", "1" do
- app 'production'
+ app "production"
assert ActiveSupport::Logger.logger_outputs_to?(app.config.logger, STDOUT)
end
end
@@ -364,139 +555,103 @@ module ApplicationTests
with_rails_env "production" do
switch_env "RAILS_SERVE_STATIC_FILES", " " do
- app 'production'
+ app "production"
assert_not app.config.public_file_server.enabled
end
end
end
- test "config.serve_static_files is deprecated" do
- make_basic_app do |application|
- assert_deprecated do
- application.config.serve_static_files = true
- end
-
- assert application.config.public_file_server.enabled
- end
- end
-
- test "config.static_cache_control is deprecated" do
- make_basic_app do |application|
- assert_deprecated do
- application.config.static_cache_control = "public, max-age=60"
- end
-
- assert_equal application.config.static_cache_control, "public, max-age=60"
- end
- end
-
test "Use key_generator when secret_key_base is set" do
make_basic_app do |application|
- application.secrets.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33'
+ application.secrets.secret_key_base = "b3c631c314c0bbca50c1b2843150fe33"
application.config.session_store :disabled
end
class ::OmgController < ActionController::Base
def index
cookies.signed[:some_key] = "some_value"
- render text: cookies[:some_key]
+ render plain: cookies[:some_key]
end
end
get "/"
- secret = app.key_generator.generate_key('signed cookie')
+ secret = app.key_generator.generate_key("signed cookie")
verifier = ActiveSupport::MessageVerifier.new(secret)
- assert_equal 'some_value', verifier.verify(last_response.body)
+ assert_equal "some_value", verifier.verify(last_response.body)
end
test "application verifier can be used in the entire application" do
make_basic_app do |application|
- application.secrets.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33'
+ application.secrets.secret_key_base = "b3c631c314c0bbca50c1b2843150fe33"
application.config.session_store :disabled
end
message = app.message_verifier(:sensitive_value).generate("some_value")
- assert_equal 'some_value', Rails.application.message_verifier(:sensitive_value).verify(message)
+ assert_equal "some_value", Rails.application.message_verifier(:sensitive_value).verify(message)
- secret = app.key_generator.generate_key('sensitive_value')
+ secret = app.key_generator.generate_key("sensitive_value")
verifier = ActiveSupport::MessageVerifier.new(secret)
- assert_equal 'some_value', verifier.verify(message)
+ 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.config.secret_token = "b3c631c314c0bbca50c1b2843150fe33"
+ test "application will generate secret_key_base in tmp file if blank in development" do
+ app_file "config/initializers/secret_token.rb", <<-RUBY
+ Rails.application.credentials.secret_key_base = nil
RUBY
- app_file 'config/secrets.yml', <<-YAML
- development:
- secret_key_base:
- YAML
- app 'development'
+ # For test that works even if tmp dir does not exist.
+ Dir.chdir(app_path) { FileUtils.remove_dir("tmp") }
- assert_equal app.env_config['action_dispatch.key_generator'], Rails.application.key_generator
- assert_equal app.env_config['action_dispatch.key_generator'].class, ActiveSupport::LegacyKeyGenerator
- message = app.message_verifier(:sensitive_value).generate("some_value")
- assert_equal 'some_value', Rails.application.message_verifier(:sensitive_value).verify(message)
+ app "development"
+
+ assert_not_nil app.secrets.secret_key_base
+ assert File.exist?(app_path("tmp/development_secret.txt"))
end
- test "warns when secrets.secret_key_base is blank and config.secret_token is set" do
- app_file 'config/initializers/secret_token.rb', <<-RUBY
- Rails.application.config.secret_token = "b3c631c314c0bbca50c1b2843150fe33"
+ test "application will not generate secret_key_base in tmp file if blank in production" do
+ app_file "config/initializers/secret_token.rb", <<-RUBY
+ Rails.application.credentials.secret_key_base = nil
RUBY
- app_file 'config/secrets.yml', <<-YAML
- development:
- secret_key_base:
- YAML
- app 'development'
-
- assert_deprecated(/You didn't set `secret_key_base`./) do
- app.env_config
+ assert_raises ArgumentError do
+ app "production"
end
end
- test "raise when secrets.secret_key_base is not a type of string" do
- app_file 'config/secrets.yml', <<-YAML
- development:
- secret_key_base: 123
- YAML
-
- app 'development'
+ test "raises when secret_key_base is blank" do
+ app_file "config/initializers/secret_token.rb", <<-RUBY
+ Rails.application.credentials.secret_key_base = nil
+ RUBY
- assert_raise(ArgumentError) do
- app.key_generator
+ error = assert_raise(ArgumentError) do
+ app "production"
end
+ assert_match(/Missing `secret_key_base`./, error.message)
end
- test "prefer secrets.secret_token over config.secret_token" do
- app_file 'config/initializers/secret_token.rb', <<-RUBY
- Rails.application.config.secret_token = ""
+ test "raise when secret_key_base is not a type of string" do
+ add_to_config <<-RUBY
+ Rails.application.credentials.secret_key_base = 123
RUBY
- app_file 'config/secrets.yml', <<-YAML
- development:
- secret_token: 3b7cd727ee24e8444053437c36cc66c3
- YAML
-
- app 'development'
- assert_equal '3b7cd727ee24e8444053437c36cc66c3', app.secrets.secret_token
+ assert_raise(ArgumentError) do
+ app "production"
+ end
end
test "application verifier can build different verifiers" do
make_basic_app do |application|
- application.secrets.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33'
application.config.session_store :disabled
end
default_verifier = app.message_verifier(:sensitive_value)
text_verifier = app.message_verifier(:text)
- message = text_verifier.generate('some_value')
+ message = text_verifier.generate("some_value")
- assert_equal 'some_value', text_verifier.verify(message)
+ assert_equal "some_value", text_verifier.verify(message)
assert_raises ActiveSupport::MessageVerifier::InvalidSignature do
default_verifier.verify(message)
end
@@ -506,110 +661,122 @@ module ApplicationTests
end
test "secrets.secret_key_base is used when config/secrets.yml is present" do
- app_file 'config/secrets.yml', <<-YAML
+ app_file "config/secrets.yml", <<-YAML
development:
secret_key_base: 3b7cd727ee24e8444053437c36cc66c3
YAML
- app 'development'
- assert_equal '3b7cd727ee24e8444053437c36cc66c3', app.secrets.secret_key_base
+ app "development"
+ assert_equal "3b7cd727ee24e8444053437c36cc66c3", app.secrets.secret_key_base
+ assert_equal "3b7cd727ee24e8444053437c36cc66c3", app.secret_key_base
end
test "secret_key_base is copied from config to secrets when not set" do
remove_file "config/secrets.yml"
- app_file 'config/initializers/secret_token.rb', <<-RUBY
+ app_file "config/initializers/secret_token.rb", <<-RUBY
Rails.application.config.secret_key_base = "3b7cd727ee24e8444053437c36cc66c3"
RUBY
- app 'development'
- assert_equal '3b7cd727ee24e8444053437c36cc66c3', app.secrets.secret_key_base
+ app "development"
+ 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
+ test "custom secrets saved in config/secrets.yml are loaded in app secrets" do
+ app_file "config/secrets.yml", <<-YAML
development:
- secret_key_base:
- secret_token:
+ secret_key_base: 3b7cd727ee24e8444053437c36cc66c3
+ aws_access_key_id: myamazonaccesskeyid
+ aws_secret_access_key: myamazonsecretaccesskey
YAML
- app 'development'
+ app "development"
- assert_equal 'b3c631c314c0bbca50c1b2843150fe33', app.secrets.secret_token
- assert_equal 'b3c631c314c0bbca50c1b2843150fe33', app.config.secret_token
+ assert_equal "myamazonaccesskeyid", app.secrets.aws_access_key_id
+ assert_equal "myamazonsecretaccesskey", app.secrets.aws_secret_access_key
end
- test "custom secrets saved in config/secrets.yml are loaded in app secrets" do
- app_file 'config/secrets.yml', <<-YAML
+ test "shared secrets saved in config/secrets.yml are loaded in app secrets" do
+ app_file "config/secrets.yml", <<-YAML
+ shared:
+ api_key: 3b7cd727
+ YAML
+
+ app "development"
+
+ assert_equal "3b7cd727", app.secrets.api_key
+ end
+
+ test "shared secrets will yield to environment specific secrets" do
+ app_file "config/secrets.yml", <<-YAML
+ shared:
+ api_key: 3b7cd727
+
development:
- secret_key_base: 3b7cd727ee24e8444053437c36cc66c3
- aws_access_key_id: myamazonaccesskeyid
- aws_secret_access_key: myamazonsecretaccesskey
+ api_key: abc12345
YAML
- app 'development'
+ app "development"
- assert_equal 'myamazonaccesskeyid', app.secrets.aws_access_key_id
- assert_equal 'myamazonsecretaccesskey', app.secrets.aws_secret_access_key
+ assert_equal "abc12345", app.secrets.api_key
end
test "blank config/secrets.yml does not crash the loading process" do
- app_file 'config/secrets.yml', <<-YAML
+ app_file "config/secrets.yml", <<-YAML
YAML
- app 'development'
+ app "development"
assert_nil app.secrets.not_defined
end
test "config.secret_key_base over-writes a blank secrets.secret_key_base" do
- app_file 'config/initializers/secret_token.rb', <<-RUBY
+ app_file "config/initializers/secret_token.rb", <<-RUBY
Rails.application.config.secret_key_base = "iaminallyoursecretkeybase"
RUBY
- app_file 'config/secrets.yml', <<-YAML
+ app_file "config/secrets.yml", <<-YAML
development:
secret_key_base:
YAML
- app 'development'
+ app "development"
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.config.secret_token = "b3c631c314c0bbca50c1b2843150fe33"
- RUBY
- app_file 'config/secrets.yml', <<-YAML
+ 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:
- secret_key_base:
+ smtp_settings:
+ address: "smtp.example.com"
+ user_name: "postmaster@example.com"
+ password: "697361616320736c6f616e2028656c6f7265737429"
YAML
- app 'development'
+ app "development"
- assert_equal 'b3c631c314c0bbca50c1b2843150fe33', app.config.secret_token
- assert_equal nil, app.secrets.secret_key_base
- assert_equal app.key_generator.class, ActiveSupport::LegacyKeyGenerator
+ assert_equal "697361616320736c6f616e2028656c6f7265737429", app.secrets.smtp_settings[:password]
end
- test "uses ActiveSupport::LegacyKeyGenerator with config.secret_token as app.key_generator when secrets.secret_key_base is blank" do
- app_file 'config/initializers/secret_token.rb', <<-RUBY
- Rails.application.config.secret_token = ""
- RUBY
- app_file 'config/secrets.yml', <<-YAML
- development:
- secret_key_base:
- YAML
+ test "require_master_key aborts app boot when missing key" do
+ skip "can't run without fork" unless Process.respond_to?(:fork)
- app 'development'
+ remove_file "config/master.key"
+ add_to_config "config.require_master_key = true"
- assert_equal '', app.config.secret_token
- assert_equal nil, app.secrets.secret_key_base
- assert_raise ArgumentError, /\AA secret is required/ do
- app.key_generator
+ error = capture(:stderr) do
+ Process.wait(Process.fork { app "development" })
end
+
+ assert_equal 1, $?.exitstatus
+ assert_match(/Missing.*RAILS_MASTER_KEY/, error)
+ end
+
+ test "credentials does not raise error when require_master_key is false and master key does not exist" do
+ remove_file "config/master.key"
+ add_to_config "config.require_master_key = false"
+ app "development"
+
+ assert_not app.credentials.secret_key_base
end
test "protect from forgery is the default in a new app" do
@@ -626,7 +793,7 @@ module ApplicationTests
end
test "default form builder specified as a string" do
- app_file 'config/initializers/form_builder.rb', <<-RUBY
+ app_file "config/initializers/form_builder.rb", <<-RUBY
class CustomFormBuilder < ActionView::Helpers::FormBuilder
def text_field(attribute, *args)
label(attribute) + super(attribute, *args)
@@ -635,15 +802,14 @@ module ApplicationTests
Rails.configuration.action_view.default_form_builder = "CustomFormBuilder"
RUBY
- app_file 'app/models/post.rb', <<-RUBY
+ app_file "app/models/post.rb", <<-RUBY
class Post
include ActiveModel::Model
attr_accessor :name
end
RUBY
-
- app_file 'app/controllers/posts_controller.rb', <<-RUBY
+ app_file "app/controllers/posts_controller.rb", <<-RUBY
class PostsController < ApplicationController
def index
render inline: "<%= begin; form_for(Post.new) {|f| f.text_field(:name)}; rescue => e; e.to_s; end %>"
@@ -657,14 +823,136 @@ module ApplicationTests
end
RUBY
- app 'development'
+ app "development"
get "/posts"
assert_match(/label/, last_response.body)
end
+ test "form_with can be configured with form_with_generates_ids" do
+ app_file "config/initializers/form_builder.rb", <<-RUBY
+ Rails.configuration.action_view.form_with_generates_ids = false
+ RUBY
+
+ app_file "app/models/post.rb", <<-RUBY
+ class Post
+ include ActiveModel::Model
+ attr_accessor :name
+ end
+ RUBY
+
+ app_file "app/controllers/posts_controller.rb", <<-RUBY
+ class PostsController < ApplicationController
+ def index
+ render inline: "<%= begin; form_with(model: Post.new) {|f| f.text_field(:name)}; rescue => e; e.to_s; end %>"
+ end
+ end
+ RUBY
+
+ add_to_config <<-RUBY
+ routes.prepend do
+ resources :posts
+ end
+ RUBY
+
+ app "development"
+
+ get "/posts"
+
+ assert_no_match(/id=('|")post_name('|")/, last_response.body)
+ end
+
+ test "form_with outputs ids by default" do
+ app_file "app/models/post.rb", <<-RUBY
+ class Post
+ include ActiveModel::Model
+ attr_accessor :name
+ end
+ RUBY
+
+ app_file "app/controllers/posts_controller.rb", <<-RUBY
+ class PostsController < ApplicationController
+ def index
+ render inline: "<%= begin; form_with(model: Post.new) {|f| f.text_field(:name)}; rescue => e; e.to_s; end %>"
+ end
+ end
+ RUBY
+
+ add_to_config <<-RUBY
+ routes.prepend do
+ resources :posts
+ end
+ RUBY
+
+ app "development"
+
+ get "/posts"
+
+ assert_match(/id=('|")post_name('|")/, last_response.body)
+ end
+
+ test "form_with can be configured with form_with_generates_remote_forms" do
+ app_file "config/initializers/form_builder.rb", <<-RUBY
+ Rails.configuration.action_view.form_with_generates_remote_forms = false
+ RUBY
+
+ app_file "app/models/post.rb", <<-RUBY
+ class Post
+ include ActiveModel::Model
+ attr_accessor :name
+ end
+ RUBY
+
+ app_file "app/controllers/posts_controller.rb", <<-RUBY
+ class PostsController < ApplicationController
+ def index
+ render inline: "<%= begin; form_with(model: Post.new) {|f| f.text_field(:name)}; rescue => e; e.to_s; end %>"
+ end
+ end
+ RUBY
+
+ add_to_config <<-RUBY
+ routes.prepend do
+ resources :posts
+ end
+ RUBY
+
+ app "development"
+
+ get "/posts"
+ assert_no_match(/data-remote/, last_response.body)
+ end
+
+ test "form_with generates remote forms by default" do
+ app_file "app/models/post.rb", <<-RUBY
+ class Post
+ include ActiveModel::Model
+ attr_accessor :name
+ end
+ RUBY
+
+ app_file "app/controllers/posts_controller.rb", <<-RUBY
+ class PostsController < ApplicationController
+ def index
+ render inline: "<%= begin; form_with(model: Post.new) {|f| f.text_field(:name)}; rescue => e; e.to_s; end %>"
+ end
+ end
+ RUBY
+
+ add_to_config <<-RUBY
+ routes.prepend do
+ resources :posts
+ end
+ RUBY
+
+ app "development"
+
+ get "/posts"
+ assert_match(/data-remote/, last_response.body)
+ end
+
test "default method for update can be changed" do
- app_file 'app/models/post.rb', <<-RUBY
+ app_file "app/models/post.rb", <<-RUBY
class Post
include ActiveModel::Model
def to_key; [1]; end
@@ -674,19 +962,19 @@ module ApplicationTests
token = "cf50faa3fe97702ca1ae"
- app_file 'app/controllers/posts_controller.rb', <<-RUBY
+ app_file "app/controllers/posts_controller.rb", <<-RUBY
class PostsController < ApplicationController
def show
render inline: "<%= begin; form_for(Post.new) {}; rescue => e; e.to_s; end %>"
end
def update
- render text: "update"
+ render plain: "update"
end
private
- def form_authenticity_token(*args); token; end # stub the authenticy token
+ def form_authenticity_token(*args); token; end # stub the authenticity token
end
RUBY
@@ -696,7 +984,7 @@ module ApplicationTests
end
RUBY
- app 'development'
+ app "development"
params = { authenticity_token: token }
@@ -718,7 +1006,7 @@ module ApplicationTests
test "request forgery token param can be changed" do
make_basic_app do |application|
- application.config.action_controller.request_forgery_protection_token = '_xsrf_token_here'
+ application.config.action_controller.request_forgery_protection_token = "_xsrf_token_here"
end
class ::OmgController < ActionController::Base
@@ -749,12 +1037,12 @@ module ApplicationTests
config.action_mailer.interceptors = MyMailInterceptor
RUBY
- app 'development'
+ app "development"
require "mail"
_ = ActionMailer::Base
- assert_equal [::MyMailInterceptor], ::Mail.send(:class_variable_get, "@@delivery_interceptors")
+ assert_equal [::MyMailInterceptor], ::Mail.class_variable_get(:@@delivery_interceptors)
end
test "registers multiple interceptors with ActionMailer" do
@@ -762,12 +1050,12 @@ module ApplicationTests
config.action_mailer.interceptors = [MyMailInterceptor, "MyOtherMailInterceptor"]
RUBY
- app 'development'
+ app "development"
require "mail"
_ = ActionMailer::Base
- assert_equal [::MyMailInterceptor, ::MyOtherMailInterceptor], ::Mail.send(:class_variable_get, "@@delivery_interceptors")
+ assert_equal [::MyMailInterceptor, ::MyOtherMailInterceptor], ::Mail.class_variable_get(:@@delivery_interceptors)
end
test "registers preview interceptors with ActionMailer" do
@@ -775,7 +1063,7 @@ module ApplicationTests
config.action_mailer.preview_interceptors = MyPreviewMailInterceptor
RUBY
- app 'development'
+ app "development"
require "mail"
_ = ActionMailer::Base
@@ -788,7 +1076,7 @@ module ApplicationTests
config.action_mailer.preview_interceptors = [MyPreviewMailInterceptor, "MyOtherPreviewMailInterceptor"]
RUBY
- app 'development'
+ app "development"
require "mail"
_ = ActionMailer::Base
@@ -797,11 +1085,11 @@ module ApplicationTests
end
test "default preview interceptor can be removed" do
- app_file 'config/initializers/preview_interceptors.rb', <<-RUBY
+ app_file "config/initializers/preview_interceptors.rb", <<-RUBY
ActionMailer::Base.preview_interceptors.delete(ActionMailer::InlinePreviewInterceptor)
RUBY
- app 'development'
+ app "development"
require "mail"
_ = ActionMailer::Base
@@ -814,12 +1102,12 @@ module ApplicationTests
config.action_mailer.observers = MyMailObserver
RUBY
- app 'development'
+ app "development"
require "mail"
_ = ActionMailer::Base
- assert_equal [::MyMailObserver], ::Mail.send(:class_variable_get, "@@delivery_notification_observers")
+ assert_equal [::MyMailObserver], ::Mail.class_variable_get(:@@delivery_notification_observers)
end
test "registers multiple observers with ActionMailer" do
@@ -827,12 +1115,12 @@ module ApplicationTests
config.action_mailer.observers = [MyMailObserver, "MyOtherMailObserver"]
RUBY
- app 'development'
+ app "development"
require "mail"
_ = ActionMailer::Base
- assert_equal [::MyMailObserver, ::MyOtherMailObserver], ::Mail.send(:class_variable_get, "@@delivery_notification_observers")
+ assert_equal [::MyMailObserver, ::MyOtherMailObserver], ::Mail.class_variable_get(:@@delivery_notification_observers)
end
test "allows setting the queue name for the ActionMailer::DeliveryJob" do
@@ -840,12 +1128,12 @@ module ApplicationTests
config.action_mailer.deliver_later_queue_name = 'test_default'
RUBY
- app 'development'
+ app "development"
require "mail"
_ = ActionMailer::Base
- assert_equal 'test_default', ActionMailer::Base.send(:class_variable_get, "@@deliver_later_queue_name")
+ assert_equal "test_default", ActionMailer::Base.class_variable_get(:@@deliver_later_queue_name)
end
test "valid timezone is setup correctly" do
@@ -854,7 +1142,7 @@ module ApplicationTests
config.time_zone = "Wellington"
RUBY
- app 'development'
+ app "development"
assert_equal "Wellington", Rails.application.config.time_zone
end
@@ -866,7 +1154,7 @@ module ApplicationTests
RUBY
assert_raise(ArgumentError) do
- app 'development'
+ app "development"
end
end
@@ -876,7 +1164,7 @@ module ApplicationTests
config.beginning_of_week = :wednesday
RUBY
- app 'development'
+ app "development"
assert_equal :wednesday, Rails.application.config.beginning_of_week
end
@@ -888,15 +1176,47 @@ module ApplicationTests
RUBY
assert_raise(ArgumentError) do
- app 'development'
+ app "development"
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
+ assert_equal ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector, Rails.autoloaders.main.inflector
+ assert_equal ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector, Rails.autoloaders.once.inflector
+
+ 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_equal ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector, Rails.autoloaders.main.inflector
+ assert_equal ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector, Rails.autoloaders.once.inflector
+
+ 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"
- app 'development'
- require 'action_view/base'
+ app "development"
+ require "action_view/base"
assert_equal true, ActionView::Resolver.caching?
end
@@ -904,8 +1224,8 @@ module ApplicationTests
test "config.action_view.cache_template_loading without cache_classes default" do
add_to_config "config.cache_classes = false"
- app 'development'
- require 'action_view/base'
+ app "development"
+ require "action_view/base"
assert_equal false, ActionView::Resolver.caching?
end
@@ -916,8 +1236,8 @@ module ApplicationTests
config.action_view.cache_template_loading = false
RUBY
- app 'development'
- require 'action_view/base'
+ app "development"
+ require "action_view/base"
assert_equal false, ActionView::Resolver.caching?
end
@@ -928,8 +1248,8 @@ module ApplicationTests
config.action_view.cache_template_loading = true
RUBY
- app 'development'
- require 'action_view/base'
+ app "development"
+ require "action_view/base"
assert_equal true, ActionView::Resolver.caching?
end
@@ -939,11 +1259,11 @@ module ApplicationTests
add_to_env_config "development", "config.cache_classes = false"
# These requires are to emulate an engine loading Action View before the application
- require 'action_view'
- require 'action_view/railtie'
- require 'action_view/base'
+ require "action_view"
+ require "action_view/railtie"
+ require "action_view/base"
- app 'development'
+ app "development"
assert_equal false, ActionView::Resolver.caching?
end
@@ -955,20 +1275,20 @@ module ApplicationTests
class ::OmgController < ActionController::Base
def index
- render text: env["action_dispatch.show_exceptions"]
+ render plain: request.env["action_dispatch.show_exceptions"]
end
end
get "/"
- assert_equal 'true', last_response.body
+ assert_equal "true", last_response.body
end
test "config.action_controller.wrap_parameters is set in ActionController::Base" do
- app_file 'config/initializers/wrap_parameters.rb', <<-RUBY
+ app_file "config/initializers/wrap_parameters.rb", <<-RUBY
ActionController::Base.wrap_parameters format: [:json]
RUBY
- app_file 'app/models/post.rb', <<-RUBY
+ app_file "app/models/post.rb", <<-RUBY
class Post
def self.attribute_names
%w(title)
@@ -976,16 +1296,16 @@ module ApplicationTests
end
RUBY
- app_file 'app/controllers/application_controller.rb', <<-RUBY
+ app_file "app/controllers/application_controller.rb", <<-RUBY
class ApplicationController < ActionController::Base
protect_from_forgery with: :reset_session # as we are testing API here
end
RUBY
- app_file 'app/controllers/posts_controller.rb', <<-RUBY
+ app_file "app/controllers/posts_controller.rb", <<-RUBY
class PostsController < ApplicationController
def create
- render text: params[:post].inspect
+ render plain: params[:post].inspect
end
end
RUBY
@@ -996,17 +1316,17 @@ module ApplicationTests
end
RUBY
- app 'development'
+ app "development"
post "/posts.json", '{ "title": "foo", "name": "bar" }', "CONTENT_TYPE" => "application/json"
assert_equal '<ActionController::Parameters {"title"=>"foo"} permitted: false>', last_response.body
end
test "config.action_controller.permit_all_parameters = true" do
- app_file 'app/controllers/posts_controller.rb', <<-RUBY
+ app_file "app/controllers/posts_controller.rb", <<-RUBY
class PostsController < ActionController::Base
def create
- render text: params[:post].permitted? ? "permitted" : "forbidden"
+ render plain: params[:post].permitted? ? "permitted" : "forbidden"
end
end
RUBY
@@ -1018,17 +1338,17 @@ module ApplicationTests
config.action_controller.permit_all_parameters = true
RUBY
- app 'development'
+ app "development"
- post "/posts", {post: {"title" =>"zomg"}}
- assert_equal 'permitted', last_response.body
+ post "/posts", post: { "title" => "zomg" }
+ assert_equal "permitted", last_response.body
end
test "config.action_controller.action_on_unpermitted_parameters = :raise" do
- app_file 'app/controllers/posts_controller.rb', <<-RUBY
+ app_file "app/controllers/posts_controller.rb", <<-RUBY
class PostsController < ActionController::Base
def create
- render text: params.require(:post).permit(:name)
+ render plain: params.require(:post).permit(:name)
end
end
RUBY
@@ -1040,16 +1360,23 @@ module ApplicationTests
config.action_controller.action_on_unpermitted_parameters = :raise
RUBY
- app 'development'
+ app "development"
+
+ force_lazy_load_hooks { ActionController::Base }
+ force_lazy_load_hooks { ActionController::API }
assert_equal :raise, ActionController::Parameters.action_on_unpermitted_parameters
- post "/posts", {post: {"title" =>"zomg"}}
+ post "/posts", post: { "title" => "zomg" }
assert_match "We're sorry, but something went wrong", last_response.body
end
test "config.action_controller.always_permitted_parameters are: controller, action by default" do
- app 'development'
+ app "development"
+
+ force_lazy_load_hooks { ActionController::Base }
+ force_lazy_load_hooks { ActionController::API }
+
assert_equal %w(controller action), ActionController::Parameters.always_permitted_parameters
end
@@ -1058,16 +1385,19 @@ module ApplicationTests
config.action_controller.always_permitted_parameters = %w( controller action format )
RUBY
- app 'development'
+ app "development"
+
+ force_lazy_load_hooks { ActionController::Base }
+ force_lazy_load_hooks { ActionController::API }
assert_equal %w( controller action format ), ActionController::Parameters.always_permitted_parameters
end
- test "config.action_controller.always_permitted_parameters = ['controller','action','format'] does not raise exeception" do
- app_file 'app/controllers/posts_controller.rb', <<-RUBY
+ test "config.action_controller.always_permitted_parameters = ['controller','action','format'] does not raise exception" do
+ app_file "app/controllers/posts_controller.rb", <<-RUBY
class PostsController < ActionController::Base
def create
- render text: params.permit(post: [:title])
+ render plain: params.permit(post: [:title])
end
end
RUBY
@@ -1080,32 +1410,87 @@ module ApplicationTests
config.action_controller.action_on_unpermitted_parameters = :raise
RUBY
- app 'development'
+ app "development"
+
+ force_lazy_load_hooks { ActionController::Base }
+ force_lazy_load_hooks { ActionController::API }
assert_equal :raise, ActionController::Parameters.action_on_unpermitted_parameters
- post "/posts", {post: {"title" =>"zomg"}, format: "json"}
+ post "/posts", post: { "title" => "zomg" }, format: "json"
assert_equal 200, last_response.status
end
- test "config.action_controller.action_on_unpermitted_parameters is :log by default on development" do
- app 'development'
+ test "config.action_controller.action_on_unpermitted_parameters is :log by default in development" do
+ app "development"
+
+ force_lazy_load_hooks { ActionController::Base }
+ force_lazy_load_hooks { ActionController::API }
assert_equal :log, ActionController::Parameters.action_on_unpermitted_parameters
end
- test "config.action_controller.action_on_unpermitted_parameters is :log by default on test" do
- app 'test'
+ test "config.action_controller.action_on_unpermitted_parameters is :log by default in test" do
+ app "test"
+
+ force_lazy_load_hooks { ActionController::Base }
+ force_lazy_load_hooks { ActionController::API }
assert_equal :log, ActionController::Parameters.action_on_unpermitted_parameters
end
- test "config.action_controller.action_on_unpermitted_parameters is false by default on production" do
- app 'production'
+ test "config.action_controller.action_on_unpermitted_parameters is false by default in production" do
+ app "production"
+
+ force_lazy_load_hooks { ActionController::Base }
+ force_lazy_load_hooks { ActionController::API }
assert_equal false, ActionController::Parameters.action_on_unpermitted_parameters
end
+ test "config.action_controller.default_protect_from_forgery is true by default" do
+ app "development"
+
+ assert_equal true, ActionController::Base.default_protect_from_forgery
+ assert_includes ActionController::Base.__callbacks[:process_action].map(&:filter), :verify_authenticity_token
+ end
+
+ test "config.action_controller.permit_all_parameters can be configured in an initializer" do
+ app_file "config/initializers/permit_all_parameters.rb", <<-RUBY
+ Rails.application.config.action_controller.permit_all_parameters = true
+ RUBY
+
+ app "development"
+
+ force_lazy_load_hooks { ActionController::Base }
+ force_lazy_load_hooks { ActionController::API }
+ assert_equal true, ActionController::Parameters.permit_all_parameters
+ end
+
+ test "config.action_controller.always_permitted_parameters can be configured in an initializer" do
+ app_file "config/initializers/always_permitted_parameters.rb", <<-RUBY
+ Rails.application.config.action_controller.always_permitted_parameters = []
+ RUBY
+
+ app "development"
+
+ force_lazy_load_hooks { ActionController::Base }
+ force_lazy_load_hooks { ActionController::API }
+ assert_equal [], ActionController::Parameters.always_permitted_parameters
+ end
+
+ test "config.action_controller.action_on_unpermitted_parameters can be configured in an initializer" do
+ app_file "config/initializers/action_on_unpermitted_parameters.rb", <<-RUBY
+ Rails.application.config.action_controller.action_on_unpermitted_parameters = :raise
+ RUBY
+
+ app "development"
+
+ force_lazy_load_hooks { ActionController::Base }
+ force_lazy_load_hooks { ActionController::API }
+ assert_equal :raise, ActionController::Parameters.action_on_unpermitted_parameters
+ end
+
test "config.action_dispatch.ignore_accept_header" do
make_basic_app do |application|
application.config.action_dispatch.ignore_accept_header = true
@@ -1114,28 +1499,27 @@ module ApplicationTests
class ::OmgController < ActionController::Base
def index
respond_to do |format|
- format.html { render text: "HTML" }
- format.xml { render text: "XML" }
+ format.html { render plain: "HTML" }
+ format.xml { render plain: "XML" }
end
end
end
- get "/", {}, "HTTP_ACCEPT" => "application/xml"
- assert_equal 'HTML', last_response.body
+ get "/", {}, { "HTTP_ACCEPT" => "application/xml" }
+ assert_equal "HTML", last_response.body
- get "/", { format: :xml }, "HTTP_ACCEPT" => "application/xml"
- assert_equal 'XML', last_response.body
+ get "/", { format: :xml }, { "HTTP_ACCEPT" => "application/xml" }
+ assert_equal "XML", last_response.body
end
- test "Rails.application#env_config exists and include some existing parameters" do
+ test "Rails.application#env_config exists and includes some existing parameters" do
make_basic_app
- assert_respond_to app, :env_config
- assert_equal app.env_config['action_dispatch.parameter_filter'], app.config.filter_parameters
- assert_equal app.env_config['action_dispatch.show_exceptions'], app.config.action_dispatch.show_exceptions
- assert_equal app.env_config['action_dispatch.logger'], Rails.logger
- assert_equal app.env_config['action_dispatch.backtrace_cleaner'], Rails.backtrace_cleaner
- assert_equal app.env_config['action_dispatch.key_generator'], Rails.application.key_generator
+ assert_equal app.env_config["action_dispatch.parameter_filter"], app.config.filter_parameters
+ assert_equal app.env_config["action_dispatch.show_exceptions"], app.config.action_dispatch.show_exceptions
+ assert_equal app.env_config["action_dispatch.logger"], Rails.logger
+ assert_equal app.env_config["action_dispatch.backtrace_cleaner"], Rails.backtrace_cleaner
+ assert_equal app.env_config["action_dispatch.key_generator"], Rails.application.key_generator
end
test "config.colorize_logging default is true" do
@@ -1144,22 +1528,37 @@ 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
- assert_raise RuntimeError, /activerecord-session_store/ do
+ e = assert_raise RuntimeError do
make_basic_app do |application|
application.config.session_store :active_record_store
end
end
+ assert_match(/activerecord-session_store/, e.message)
+ end
+
+ test "default session store initializer does not overwrite the user defined session store even if it is disabled" do
+ make_basic_app do |application|
+ application.config.session_store :disabled
+ end
+
+ assert_nil app.config.session_store
+ end
+
+ test "default session store initializer sets session store to cookie store" do
+ session_options = { key: "_myapp_session", cookie_only: true }
+ make_basic_app
+
+ assert_equal ActionDispatch::Session::CookieStore, app.config.session_store
+ assert_equal session_options, app.config.session_options
end
test "config.log_level with custom logger" do
@@ -1173,24 +1572,30 @@ module ApplicationTests
test "respond_to? accepts include_private" do
make_basic_app
- assert_not Rails.configuration.respond_to?(:method_missing)
+ assert_not_respond_to Rails.configuration, :method_missing
assert Rails.configuration.respond_to?(:method_missing, true)
end
test "config.active_record.dump_schema_after_migration is false on production" do
build_app
- app 'production'
+ app "production"
assert_not ActiveRecord::Base.dump_schema_after_migration
end
- test "config.active_record.dump_schema_after_migration is true by default on development" do
- app 'development'
+ test "config.active_record.dump_schema_after_migration is true by default in development" do
+ app "development"
assert ActiveRecord::Base.dump_schema_after_migration
end
+ test "config.active_record.verbose_query_logs is false by default in development" do
+ app "development"
+
+ assert_not ActiveRecord::Base.verbose_query_logs
+ end
+
test "config.annotations wrapping SourceAnnotationExtractor::Annotation class" do
make_basic_app do |application|
application.config.annotations.register_extensions("coffee") do |tag|
@@ -1198,7 +1603,7 @@ module ApplicationTests
end
end
- assert_not_nil SourceAnnotationExtractor::Annotation.extensions[/\.(coffee)$/]
+ assert_not_nil Rails::SourceAnnotationExtractor::Annotation.extensions[/\.(coffee)$/]
end
test "rake_tasks block works at instance level" do
@@ -1212,12 +1617,12 @@ module ApplicationTests
end
RUBY
- app 'development'
+ app "development"
assert_not Rails.configuration.ran_block
- require 'rake'
- require 'rake/testtask'
- require 'rdoc/task'
+ require "rake"
+ require "rake/testtask"
+ require "rdoc/task"
Rails.application.load_tasks
assert Rails.configuration.ran_block
@@ -1234,7 +1639,7 @@ module ApplicationTests
end
RUBY
- app 'development'
+ app "development"
assert_not Rails.configuration.ran_block
Rails.application.load_generators
@@ -1252,7 +1657,7 @@ module ApplicationTests
end
RUBY
- app 'development'
+ app "development"
assert_not Rails.configuration.ran_block
Rails.application.load_console
@@ -1270,7 +1675,7 @@ module ApplicationTests
end
RUBY
- app 'development'
+ app "development"
assert_not Rails.configuration.ran_block
Rails.application.load_runner
@@ -1278,7 +1683,7 @@ module ApplicationTests
end
test "loading the first existing database configuration available" do
- app_file 'config/environments/development.rb', <<-RUBY
+ app_file "config/environments/development.rb", <<-RUBY
Rails.application.configure do
config.paths.add 'config/database', with: 'config/nonexistent.yml'
@@ -1286,59 +1691,265 @@ module ApplicationTests
end
RUBY
- app 'development'
+ app "development"
assert_kind_of Hash, Rails.application.config.database_configuration
end
- test 'raises with proper error message if no database configuration found' do
+ 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")
- app 'development'
err = assert_raises RuntimeError do
+ app "development"
Rails.application.config.database_configuration
end
- assert_match 'config/database', err.message
+ assert_match "config/database", err.message
end
- test 'config.action_mailer.show_previews defaults to true in development' do
- app 'development'
+ test "loads database.yml using shared keys" do
+ app_file "config/database.yml", <<-YAML
+ shared:
+ username: bobby
+ adapter: sqlite3
+
+ development:
+ database: 'dev_db'
+ YAML
+
+ app "development"
+
+ ar_config = Rails.application.config.database_configuration
+ assert_equal "sqlite3", ar_config["development"]["adapter"]
+ assert_equal "bobby", ar_config["development"]["username"]
+ assert_equal "dev_db", ar_config["development"]["database"]
+ end
+
+ test "loads database.yml using shared keys for undefined environments" do
+ app_file "config/database.yml", <<-YAML
+ shared:
+ username: bobby
+ adapter: sqlite3
+ database: 'dev_db'
+ YAML
+
+ app "development"
+
+ ar_config = Rails.application.config.database_configuration
+ assert_equal "sqlite3", ar_config["development"]["adapter"]
+ assert_equal "bobby", ar_config["development"]["username"]
+ assert_equal "dev_db", ar_config["development"]["database"]
+ end
+
+ test "config.action_mailer.show_previews defaults to true in development" do
+ app "development"
assert Rails.application.config.action_mailer.show_previews
end
- test 'config.action_mailer.show_previews defaults to false in production' do
- app 'production'
+ test "config.action_mailer.show_previews defaults to false in production" do
+ app "production"
assert_equal false, Rails.application.config.action_mailer.show_previews
end
- test 'config.action_mailer.show_previews can be set in the configuration file' do
+ test "config.action_mailer.show_previews can be set in the configuration file" do
add_to_config <<-RUBY
config.action_mailer.show_previews = true
RUBY
- app 'production'
+ app "production"
assert_equal true, Rails.application.config.action_mailer.show_previews
end
- test "config_for loads custom configuration from yaml files" do
- app_file 'config/custom.yml', <<-RUBY
+ test "config_for loads custom configuration from yaml accessible as symbol or string" do
+ app_file "config/custom.yml", <<-RUBY
development:
- key: 'custom key'
+ foo: 'bar'
+ RUBY
+
+ add_to_config <<-RUBY
+ config.my_custom_config = config_for('custom')
+ RUBY
+
+ 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 nested custom configuration from yaml as symbol keys" do
+ app_file "config/custom.yml", <<-RUBY
+ development:
+ foo:
+ bar:
+ baz: 1
+ RUBY
+
+ add_to_config <<-RUBY
+ config.my_custom_config = config_for('custom')
+ RUBY
+
+ app "development"
+
+ assert_equal 1, Rails.application.config.my_custom_config[:foo][:bar][:baz]
+ end
+
+ test "config_for loads nested custom configuration from yaml with deprecated non-symbol access" do
+ app_file "config/custom.yml", <<-RUBY
+ development:
+ foo:
+ bar:
+ baz: 1
+ RUBY
+
+ add_to_config <<-RUBY
+ config.my_custom_config = config_for('custom')
+ RUBY
+
+ app "development"
+
+ assert_deprecated do
+ assert_equal 1, Rails.application.config.my_custom_config["foo"]["bar"]["baz"]
+ end
+ end
+
+ 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
RUBY
add_to_config <<-RUBY
config.my_custom_config = config_for('custom')
RUBY
- app 'development'
+ app "development"
- assert_equal 'custom key', Rails.application.config.my_custom_config['key']
+ 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
- app_file 'config/custom.yml', <<-RUBY
+ app_file "config/custom.yml", <<-RUBY
development:
key: 'custom key'
RUBY
@@ -1347,9 +1958,9 @@ module ApplicationTests
config.my_custom_config = config_for(Pathname.new(Rails.root.join("config/custom.yml")))
RUBY
- app 'development'
+ 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
@@ -1358,14 +1969,14 @@ module ApplicationTests
RUBY
exception = assert_raises(RuntimeError) do
- app 'development'
+ app "development"
end
assert_equal "Could not load configuration. No such file - #{app_path}/config/custom.yml", exception.message
end
test "config_for without the environment configured returns an empty hash" do
- app_file 'config/custom.yml', <<-RUBY
+ app_file "config/custom.yml", <<-RUBY
test:
key: 'custom key'
RUBY
@@ -1374,26 +1985,96 @@ module ApplicationTests
config.my_custom_config = config_for('custom')
RUBY
- app 'development'
+ app "development"
assert_equal({}, Rails.application.config.my_custom_config)
end
+ 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
+ config.my_custom_config = config_for('custom')
+ RUBY
+
+ app "development"
+
+ assert_equal(:bar, Rails.application.config.my_custom_config[:foo])
+ end
+
test "config_for with empty file returns an empty hash" do
- app_file 'config/custom.yml', <<-RUBY
+ app_file "config/custom.yml", <<-RUBY
RUBY
add_to_config <<-RUBY
config.my_custom_config = config_for('custom')
RUBY
- app 'development'
+ app "development"
assert_equal({}, Rails.application.config.my_custom_config)
end
+ 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"
+ assert_deprecated do
+ force_lazy_load_hooks { Post }
+ end
+ end
+
+ 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 = false
+ RUBY
+
+ app_file "app/models/post.rb", <<-RUBY
+ class Post < ActiveRecord::Base
+ end
+ RUBY
+
+ app "development"
+ assert_raises(RuntimeError) do
+ force_lazy_load_hooks { Post }
+ end
+ end
+
test "config_for containing ERB tags should evaluate" do
- app_file 'config/custom.yml', <<-RUBY
+ app_file "config/custom.yml", <<-RUBY
development:
key: <%= 'custom key' %>
RUBY
@@ -1402,13 +2083,13 @@ module ApplicationTests
config.my_custom_config = config_for('custom')
RUBY
- app 'development'
+ 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
- app_file 'config/custom.yml', <<-RUBY
+ app_file "config/custom.yml", <<-RUBY
development:
key: foo:
RUBY
@@ -1418,14 +2099,14 @@ module ApplicationTests
RUBY
exception = assert_raises(RuntimeError) do
- app 'development'
+ app "development"
end
- assert_match 'YAML syntax error occurred while parsing', exception.message
+ assert_match "YAML syntax error occurred while parsing", exception.message
end
test "config_for allows overriding the environment" do
- app_file 'config/custom.yml', <<-RUBY
+ app_file "config/custom.yml", <<-RUBY
test:
key: 'walrus'
production:
@@ -1437,19 +2118,19 @@ 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
- app 'development'
- refute Rails.application.config.api_only
+ app "development"
+ assert_not Rails.application.config.api_only
end
test "api_only generator config is set when api_only is set" do
add_to_config <<-RUBY
config.api_only = true
RUBY
- app 'development'
+ app "development"
Rails.application.load_generators
assert Rails.configuration.api_only
@@ -1459,25 +2140,361 @@ module ApplicationTests
add_to_config <<-RUBY
config.api_only = true
RUBY
- app 'development'
+ app "development"
assert_equal :api, Rails.configuration.debug_exception_response_format
end
- test "debug_exception_response_format can be overriden" do
+ test "debug_exception_response_format can be overridden" do
add_to_config <<-RUBY
config.api_only = true
RUBY
- app_file 'config/environments/development.rb', <<-RUBY
+ app_file "config/environments/development.rb", <<-RUBY
Rails.application.configure do
config.debug_exception_response_format = :default
end
RUBY
- app 'development'
+ app "development"
assert_equal :default, Rails.configuration.debug_exception_response_format
end
+
+ test "controller force_ssl declaration can be used even if session_store is disabled" do
+ make_basic_app do |application|
+ application.config.session_store :disabled
+ end
+
+ class ::OmgController < ActionController::Base
+ force_ssl
+
+ def index
+ render plain: "Yay! You're on Rails!"
+ end
+ end
+
+ get "/"
+
+ assert_equal 301, last_response.status
+ assert_equal "https://example.org/", last_response.location
+ end
+
+ test "ActiveSupport::MessageEncryptor.use_authenticated_message_encryption is true by default for new apps" do
+ app "development"
+
+ assert_equal true, ActiveSupport::MessageEncryptor.use_authenticated_message_encryption
+ end
+
+ test "ActiveSupport::MessageEncryptor.use_authenticated_message_encryption is false by default for upgraded apps" do
+ remove_from_config '.*config\.load_defaults.*\n'
+
+ app "development"
+
+ assert_equal false, ActiveSupport::MessageEncryptor.use_authenticated_message_encryption
+ end
+
+ test "ActiveSupport::MessageEncryptor.use_authenticated_message_encryption can be configured via config.active_support.use_authenticated_message_encryption" do
+ remove_from_config '.*config\.load_defaults.*\n'
+
+ app_file "config/initializers/new_framework_defaults_6_0.rb", <<-RUBY
+ Rails.application.config.active_support.use_authenticated_message_encryption = true
+ RUBY
+
+ app "development"
+
+ assert_equal true, ActiveSupport::MessageEncryptor.use_authenticated_message_encryption
+ end
+
+ test "ActiveSupport::Digest.hash_digest_class is Digest::SHA1 by default for new apps" do
+ app "development"
+
+ assert_equal Digest::SHA1, ActiveSupport::Digest.hash_digest_class
+ end
+
+ test "ActiveSupport::Digest.hash_digest_class is Digest::MD5 by default for upgraded apps" do
+ remove_from_config '.*config\.load_defaults.*\n'
+
+ app "development"
+
+ assert_equal Digest::MD5, ActiveSupport::Digest.hash_digest_class
+ end
+
+ test "ActiveSupport::Digest.hash_digest_class can be configured via config.active_support.use_sha1_digests" do
+ remove_from_config '.*config\.load_defaults.*\n'
+
+ app_file "config/initializers/new_framework_defaults_6_0.rb", <<-RUBY
+ Rails.application.config.active_support.use_sha1_digests = true
+ RUBY
+
+ app "development"
+
+ assert_equal Digest::SHA1, ActiveSupport::Digest.hash_digest_class
+ end
+
+ test "custom serializers should be able to set via config.active_job.custom_serializers in an initializer" do
+ class ::DummySerializer < ActiveJob::Serializers::ObjectSerializer; end
+
+ app_file "config/initializers/custom_serializers.rb", <<-RUBY
+ Rails.application.config.active_job.custom_serializers << DummySerializer
+ RUBY
+
+ app "development"
+
+ assert_includes ActiveJob::Serializers.serializers, DummySerializer
+ end
+
+ test "ActionView::Helpers::FormTagHelper.default_enforce_utf8 is false by default" do
+ app "development"
+ assert_equal false, ActionView::Helpers::FormTagHelper.default_enforce_utf8
+ end
+
+ test "ActionView::Helpers::FormTagHelper.default_enforce_utf8 is true in an upgraded app" do
+ remove_from_config '.*config\.load_defaults.*\n'
+ add_to_config 'config.load_defaults "5.2"'
+
+ app "development"
+
+ assert_equal true, ActionView::Helpers::FormTagHelper.default_enforce_utf8
+ end
+
+ test "ActionView::Helpers::FormTagHelper.default_enforce_utf8 can be configured via config.action_view.default_enforce_utf8" do
+ remove_from_config '.*config\.load_defaults.*\n'
+
+ app_file "config/initializers/new_framework_defaults_6_0.rb", <<-RUBY
+ Rails.application.config.action_view.default_enforce_utf8 = true
+ RUBY
+
+ app "development"
+
+ assert_equal true, ActionView::Helpers::FormTagHelper.default_enforce_utf8
+ end
+
+ test "ActionView::Template.finalize_compiled_template_methods is true by default" do
+ app "test"
+ 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
+ app_file "config/environments/test.rb", <<-RUBY
+ Rails.application.configure do
+ config.action_view.finalize_compiled_template_methods = false
+ end
+ RUBY
+
+ app "test"
+
+ 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
+ app_file "config/initializers/filter_parameters_logging.rb", <<-RUBY
+ Rails.application.config.filter_parameters += [ :password, :credit_card_number ]
+ RUBY
+ app "development"
+ assert_equal [ :password, :credit_card_number ], Rails.application.config.filter_parameters
+ 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
+ app_file "config/environments/development.rb", <<-RUBY
+ Rails.application.configure do
+ config.active_storage.routes_prefix = '/files'
+ end
+ RUBY
+
+ output = rails("routes", "-g", "active_storage")
+ assert_equal <<~MESSAGE, output
+ Prefix Verb URI Pattern Controller#Action
+ rails_service_blob GET /files/blobs/:signed_id/*filename(.:format) active_storage/blobs#show
+ rails_blob_representation GET /files/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show
+ rails_disk_service GET /files/disk/:encoded_key/*filename(.:format) active_storage/disk#show
+ update_rails_disk_service PUT /files/disk/:encoded_token(.:format) active_storage/disk#update
+ rails_direct_uploads POST /files/direct_uploads(.:format) active_storage/direct_uploads#create
+ MESSAGE
+ end
+
+ test "hosts include .localhost in development" do
+ app "development"
+ assert_includes Rails.application.config.hosts, ".localhost"
+ end
+
+ test "disable_sandbox is false by default" do
+ app "development"
+
+ assert_equal false, Rails.configuration.disable_sandbox
+ end
+
+ test "disable_sandbox can be overridden" do
+ add_to_config <<-RUBY
+ config.disable_sandbox = true
+ RUBY
+
+ app "development"
+
+ assert Rails.configuration.disable_sandbox
+ end
+
+ private
+ def force_lazy_load_hooks
+ yield # Tasty clarifying sugar, homie! We only need to reference a constant to load it.
+ end
end
end
diff --git a/railties/test/application/console_test.rb b/railties/test/application/console_test.rb
index ea68e63f8f..db16f4cc56 100644
--- a/railties/test/application/console_test.rb
+++ b/railties/test/application/console_test.rb
@@ -1,11 +1,13 @@
-require 'isolation/abstract_unit'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "console_helpers"
class ConsoleTest < ActiveSupport::TestCase
include ActiveSupport::Testing::Isolation
def setup
build_app
- boot_rails
end
def teardown
@@ -23,14 +25,14 @@ 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
end
def test_app_can_access_path_helper_method
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get 'foo', to: 'foo#index'
end
@@ -38,7 +40,7 @@ class ConsoleTest < ActiveSupport::TestCase
load_environment
console_session = irb_context.app
- assert_equal '/foo', console_session.foo_path
+ assert_equal "/foo", console_session.foo_path
end
def test_new_session_should_return_integration_session
@@ -71,7 +73,7 @@ class ConsoleTest < ActiveSupport::TestCase
MODEL
load_environment
- assert User.new.respond_to?(:name)
+ assert_respond_to User.new, :name
app_file "app/models/user.rb", <<-MODEL
class User
@@ -79,9 +81,9 @@ class ConsoleTest < ActiveSupport::TestCase
end
MODEL
- assert !User.new.respond_to?(:age)
+ assert_not_respond_to User.new, :age
irb_context.reload!(false)
- assert User.new.respond_to?(:age)
+ assert_respond_to User.new, :age
end
def test_access_to_helpers
@@ -89,76 +91,83 @@ class ConsoleTest < ActiveSupport::TestCase
helper = irb_context.helper
assert_not_nil helper
assert_instance_of ActionView::Base, helper
- assert_equal 'Once upon a time in a world...',
- helper.truncate('Once upon a time in a world far far away')
+ assert_equal "Once upon a time in a world...",
+ helper.truncate("Once upon a time in a world far far away")
end
end
-begin
- require "pty"
-rescue LoadError
-end
-
class FullStackConsoleTest < ActiveSupport::TestCase
+ include ConsoleHelpers
+
def setup
- skip "PTY unavailable" unless defined?(PTY) && PTY.respond_to?(:open)
+ skip "PTY unavailable" unless available_pty?
build_app
- app_file 'app/models/post.rb', <<-CODE
+ app_file "app/models/post.rb", <<-CODE
class Post < ActiveRecord::Base
end
CODE
system "#{app_path}/bin/rails runner 'Post.connection.create_table :posts'"
- @master, @slave = PTY.open
+ @primary, @replica = PTY.open
end
def teardown
teardown_app
end
- def assert_output(expected, timeout = 1)
- timeout = Time.now + timeout
-
- output = ""
- until output.include?(expected) || Time.now > timeout
- if IO.select([@master], [], [], 0.1)
- output << @master.read(1)
- end
- end
-
- assert output.include?(expected), "#{expected.inspect} expected, but got:\n\n#{output}"
- end
-
def write_prompt(command, expected_output = nil)
- @master.puts command
- assert_output command
- assert_output expected_output if expected_output
- assert_output "> "
+ @primary.puts command
+ assert_output command, @primary
+ assert_output expected_output, @primary if expected_output
+ assert_output "> ", @primary
end
- def spawn_console
- Process.spawn(
- "#{app_path}/bin/rails console --sandbox",
- in: @slave, out: @slave, err: @slave
+ def spawn_console(options, wait_for_prompt: true)
+ pid = Process.spawn(
+ "#{app_path}/bin/rails console #{options}",
+ in: @replica, out: @replica, err: @replica
)
- assert_output "> ", 30
+ if wait_for_prompt
+ assert_output "> ", @primary, 30
+ end
+
+ pid
end
def test_sandbox
- spawn_console
+ spawn_console("--sandbox")
write_prompt "Post.count", "=> 0"
write_prompt "Post.create"
write_prompt "Post.count", "=> 1"
- @master.puts "quit"
+ @primary.puts "quit"
- spawn_console
+ spawn_console("--sandbox")
write_prompt "Post.count", "=> 0"
write_prompt "Post.transaction { Post.create; raise }"
write_prompt "Post.count", "=> 0"
- @master.puts "quit"
+ @primary.puts "quit"
+ end
+
+ def test_sandbox_when_sandbox_is_disabled
+ add_to_config <<-RUBY
+ config.disable_sandbox = true
+ RUBY
+
+ output = `#{app_path}/bin/rails console --sandbox`
+
+ assert_includes output, "sandbox mode is disabled"
+ assert_equal 1, $?.exitstatus
+ end
+
+ def test_environment_option_and_irb_option
+ spawn_console("-e test -- --verbose")
+
+ write_prompt "a = 1", "a = 1"
+ write_prompt "puts Rails.env", "puts Rails.env\r\ntest"
+ @primary.puts "quit"
end
end
diff --git a/railties/test/application/content_security_policy_test.rb b/railties/test/application/content_security_policy_test.rb
new file mode 100644
index 0000000000..0d28df16f8
--- /dev/null
+++ b/railties/test/application/content_security_policy_test.rb
@@ -0,0 +1,223 @@
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "rack/test"
+
+module ApplicationTests
+ class ContentSecurityPolicyTest < ActiveSupport::TestCase
+ include ActiveSupport::Testing::Isolation
+ include Rack::Test::Methods
+
+ def setup
+ build_app
+ end
+
+ def teardown
+ teardown_app
+ end
+
+ test "default content security policy is nil" 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["Content-Security-Policy"]
+ end
+
+ test "empty content security policy is generated" 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|
+ end
+ RUBY
+
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ root to: "pages#index"
+ end
+ RUBY
+
+ app("development")
+
+ get "/"
+ assert_policy ""
+ end
+
+ test "global content security 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/content_security_policy.rb", <<-RUBY
+ Rails.application.config.content_security_policy do |p|
+ p.default_src :self, :https
+ end
+ 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:"
+ end
+
+ test "global report only content security 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/content_security_policy.rb", <<-RUBY
+ Rails.application.config.content_security_policy do |p|
+ p.default_src :self, :https
+ end
+
+ Rails.application.config.content_security_policy_report_only = true
+ 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:", report_only: true
+ end
+
+ test "override content security policy in a controller" do
+ controller :pages, <<-RUBY
+ class PagesController < ApplicationController
+ content_security_policy do |p|
+ p.default_src "https://example.com"
+ end
+
+ 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
+ end
+ 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 https://example.com"
+ end
+
+ test "override content security policy to report only in a controller" do
+ controller :pages, <<-RUBY
+ class PagesController < ApplicationController
+ content_security_policy_report_only
+
+ 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
+ end
+ 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:", report_only: true
+ end
+
+ test "global content security policy added to rack app" do
+ app_file "config/initializers/content_security_policy.rb", <<-RUBY
+ Rails.application.config.content_security_policy do |p|
+ p.default_src :self, :https
+ 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 "default-src 'self' https:"
+ end
+
+ private
+
+ def assert_policy(expected, report_only: false)
+ assert_equal 200, last_response.status
+
+ if report_only
+ expected_header = "Content-Security-Policy-Report-Only"
+ unexpected_header = "Content-Security-Policy"
+ else
+ expected_header = "Content-Security-Policy"
+ unexpected_header = "Content-Security-Policy-Report-Only"
+ end
+
+ assert_nil last_response.headers[unexpected_header]
+ assert_equal expected, last_response.headers[expected_header]
+ end
+ end
+end
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/current_attributes_integration_test.rb b/railties/test/application/current_attributes_integration_test.rb
new file mode 100644
index 0000000000..146e96facc
--- /dev/null
+++ b/railties/test/application/current_attributes_integration_test.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "rack/test"
+
+class CurrentAttributesIntegrationTest < ActiveSupport::TestCase
+ include ActiveSupport::Testing::Isolation
+ include Rack::Test::Methods
+
+ setup do
+ build_app
+
+ app_file "app/models/current.rb", <<-RUBY
+ class Current < ActiveSupport::CurrentAttributes
+ attribute :customer
+
+ resets { Time.zone = "UTC" }
+
+ def customer=(customer)
+ super
+ Time.zone = customer.try(:time_zone)
+ end
+ end
+ RUBY
+
+ app_file "app/models/customer.rb", <<-RUBY
+ class Customer < Struct.new(:name)
+ def time_zone
+ "Copenhagen"
+ end
+ end
+ RUBY
+
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ get "/customers/:action", controller: :customers
+ end
+ RUBY
+
+ app_file "app/controllers/customers_controller.rb", <<-RUBY
+ class CustomersController < ApplicationController
+ layout false
+
+ def set_current_customer
+ Current.customer = Customer.new("david")
+ render :index
+ end
+
+ def set_no_customer
+ render :index
+ end
+ end
+ RUBY
+
+ app_file "app/views/customers/index.html.erb", <<-RUBY
+ <%= Current.customer.try(:name) || 'noone' %>,<%= Time.zone.name %>
+ RUBY
+
+ require "#{app_path}/config/environment"
+ end
+
+ teardown :teardown_app
+
+ test "current customer is assigned and cleared" do
+ get "/customers/set_current_customer"
+ assert_equal 200, last_response.status
+ assert_match(/david,Copenhagen/, last_response.body)
+
+ get "/customers/set_no_customer"
+ assert_equal 200, last_response.status
+ assert_match(/noone,UTC/, last_response.body)
+ end
+
+ test "resets after execution" do
+ assert_nil Current.customer
+ assert_equal "UTC", Time.zone.name
+
+ Rails.application.executor.wrap do
+ Current.customer = Customer.new("david")
+
+ assert_equal "david", Current.customer.name
+ assert_equal "Copenhagen", Time.zone.name
+ end
+
+ assert_nil Current.customer
+ assert_equal "UTC", Time.zone.name
+ end
+end
diff --git a/railties/test/application/dbconsole_test.rb b/railties/test/application/dbconsole_test.rb
new file mode 100644
index 0000000000..8c03fe4ac6
--- /dev/null
+++ b/railties/test/application/dbconsole_test.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "console_helpers"
+
+module ApplicationTests
+ class DBConsoleTest < ActiveSupport::TestCase
+ include ActiveSupport::Testing::Isolation
+ include ConsoleHelpers
+
+ def setup
+ skip "PTY unavailable" unless available_pty?
+
+ build_app
+ end
+
+ def teardown
+ teardown_app
+ end
+
+ def test_use_value_defined_in_environment_file_in_database_yml
+ app_file "config/database.yml", <<-YAML
+ development:
+ database: <%= Rails.application.config.database %>
+ adapter: sqlite3
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
+ timeout: 5000
+ YAML
+
+ app_file "config/environments/development.rb", <<-RUBY
+ Rails.application.configure do
+ config.database = "db/development.sqlite3"
+ end
+ RUBY
+
+ primary, replica = PTY.open
+ spawn_dbconsole(replica)
+ assert_output("sqlite>", primary)
+ ensure
+ primary.puts ".exit"
+ end
+
+ def test_respect_environment_option
+ app_file "config/database.yml", <<-YAML
+ default: &default
+ adapter: sqlite3
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
+ timeout: 5000
+
+ development:
+ <<: *default
+ database: db/development.sqlite3
+
+ production:
+ <<: *default
+ database: db/production.sqlite3
+ YAML
+
+ primary, replica = PTY.open
+ spawn_dbconsole(replica, "-e production")
+ assert_output("sqlite>", primary)
+
+ primary.puts "pragma database_list;"
+ assert_output("production.sqlite3", primary)
+ ensure
+ primary.puts ".exit"
+ end
+
+ private
+ def spawn_dbconsole(fd, options = nil)
+ Process.spawn("#{app_path}/bin/rails dbconsole #{options}", in: fd, out: fd, err: fd)
+ end
+ end
+end
diff --git a/railties/test/application/generators_test.rb b/railties/test/application/generators_test.rb
index 644af0e737..e5e557d204 100644
--- a/railties/test/application/generators_test.rb
+++ b/railties/test/application/generators_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "isolation/abstract_unit"
module ApplicationTests
@@ -6,7 +8,6 @@ module ApplicationTests
def setup
build_app
- boot_rails
end
def teardown
@@ -30,7 +31,7 @@ module ApplicationTests
end
test "allow running plugin new generator inside Rails app directory" do
- FileUtils.cd(rails_root){ `ruby bin/rails plugin new vendor/plugins/bukkits` }
+ rails "plugin", "new", "vendor/plugins/bukkits"
assert File.exist?(File.join(rails_root, "vendor/plugins/bukkits/test/dummy/config/application.rb"))
end
@@ -114,7 +115,7 @@ module ApplicationTests
test "generators with string and hash for options should generate symbol keys" do
with_bare_config do |c|
c.generators do |g|
- g.orm 'data_mapper', migration: false
+ g.orm "data_mapper", migration: false
end
expected = {
@@ -135,10 +136,10 @@ module ApplicationTests
require "#{app_path}/config/environment"
Rails.application.load_generators
- assert Rails::Generators.hidden_namespaces.include?("assets")
- assert Rails::Generators.hidden_namespaces.include?("helper")
- assert Rails::Generators.hidden_namespaces.include?("js")
- assert Rails::Generators.hidden_namespaces.include?("css")
+ assert_includes Rails::Generators.hidden_namespaces, "assets"
+ assert_includes Rails::Generators.hidden_namespaces, "helper"
+ assert_includes Rails::Generators.hidden_namespaces, "js"
+ assert_includes Rails::Generators.hidden_namespaces, "css"
assert Rails::Generators.options[:rails][:api]
assert_equal false, Rails::Generators.options[:rails][:assets]
assert_equal false, Rails::Generators.options[:rails][:helper]
@@ -166,9 +167,36 @@ module ApplicationTests
config.api_only = true
RUBY
- FileUtils.cd(rails_root){ `bin/rails generate mailer notifier foo` }
+ rails "generate", "mailer", "notifier", "foo"
assert File.exist?(File.join(rails_root, "app/views/notifier_mailer/foo.text.erb"))
assert File.exist?(File.join(rails_root, "app/views/notifier_mailer/foo.html.erb"))
end
+
+ test "ARGV is mutated as expected" do
+ require "#{app_path}/config/environment"
+ require "rails/command"
+ Rails::Command.const_set("APP_PATH", "rails/all")
+
+ FileUtils.cd(rails_root) do
+ ARGV = ["mailer", "notifier", "foo"]
+ Rails::Command.const_set("ARGV", ARGV)
+ quietly { Rails::Command.invoke :generate, ARGV }
+
+ assert_equal ["notifier", "foo"], ARGV
+ end
+
+ Rails::Command.send(:remove_const, "APP_PATH")
+ end
+
+ test "help does not show hidden namespaces and hidden commands" do
+ FileUtils.cd(rails_root) do
+ output = rails("generate", "--help")
+ assert_no_match "active_record:migration", output
+ assert_no_match "credentials", output
+
+ output = rails("destroy", "--help")
+ assert_no_match "active_record:migration", output
+ end
+ end
end
end
diff --git a/railties/test/application/help_test.rb b/railties/test/application/help_test.rb
new file mode 100644
index 0000000000..f728fc3b85
--- /dev/null
+++ b/railties/test/application/help_test.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+
+class HelpTest < ActiveSupport::TestCase
+ include ActiveSupport::Testing::Isolation
+
+ def setup
+ build_app
+ end
+
+ def teardown
+ teardown_app
+ end
+
+ test "command works" do
+ output = rails("help")
+ assert_match "The most common rails commands are", output
+ end
+
+ test "short-cut alias works" do
+ output = rails("-h")
+ assert_match "The most common rails commands are", output
+ end
+end
diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb
index 44209a52f7..a35247fc43 100644
--- a/railties/test/application/initializers/frameworks_test.rb
+++ b/railties/test/application/initializers/frameworks_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "isolation/abstract_unit"
module ApplicationTests
@@ -6,7 +8,6 @@ module ApplicationTests
def setup
build_app
- boot_rails
FileUtils.rm_rf "#{app_path}/config/environments"
end
@@ -38,7 +39,7 @@ module ApplicationTests
assert_equal expanded_path, ActionMailer::Base.view_paths[0].to_s
end
- test "allows me to configure default url options for ActionMailer" do
+ test "allows me to configure default URL options for ActionMailer" do
app_file "config/environments/development.rb", <<-RUBY
Rails.application.configure do
config.action_mailer.default_url_options = { :host => "test.rails" }
@@ -60,7 +61,7 @@ module ApplicationTests
assert_equal "https", ActionMailer::Base.default_url_options[:protocol]
end
- test "includes url helpers as action methods" do
+ test "includes URL helpers as action methods" do
app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get "/foo", :to => lambda { |env| [200, {}, []] }, :as => :foo
@@ -129,7 +130,7 @@ module ApplicationTests
end
RUBY
- require 'rack/test'
+ require "rack/test"
extend Rack::Test::Methods
get "/foo/included_helpers"
@@ -161,10 +162,10 @@ module ApplicationTests
end
RUBY
- require 'rack/test'
+ require "rack/test"
extend Rack::Test::Methods
- get 'omg/show'
+ get "omg/show"
assert_equal '{"omg":"omg"}', last_response.body
end
@@ -176,7 +177,7 @@ module ApplicationTests
end
test "assignment config.encoding to default_charset" do
- charset = 'Shift_JIS'
+ charset = "Shift_JIS"
add_to_config "config.encoding = '#{charset}'"
require "#{app_path}/config/environment"
assert_equal charset, ActionDispatch::Response.default_charset
@@ -186,7 +187,7 @@ module ApplicationTests
test "if there's no config.active_support.bare, all of ActiveSupport is required" do
use_frameworks []
require "#{app_path}/config/environment"
- assert_nothing_raised { [1,2,3].sample }
+ assert_nothing_raised { [1, 2, 3].sample }
end
test "config.active_support.bare does not require all of ActiveSupport" do
@@ -204,66 +205,64 @@ module ApplicationTests
test "active_record extensions are applied to ActiveRecord" do
add_to_config "config.active_record.table_name_prefix = 'tbl_'"
require "#{app_path}/config/environment"
- assert_equal 'tbl_', ActiveRecord::Base.table_name_prefix
+ assert_equal "tbl_", ActiveRecord::Base.table_name_prefix
end
test "database middleware doesn't initialize when activerecord is not in frameworks" do
use_frameworks []
require "#{app_path}/config/environment"
- assert_nil defined?(ActiveRecord::Base)
+ assert !defined?(ActiveRecord::Base) || ActiveRecord.autoload?(:Base)
end
test "use schema cache dump" do
- Dir.chdir(app_path) do
- `rails generate model post title:string;
- bin/rails db:migrate db:schema:cache:dump`
- end
+ 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.tables("posts")
+ assert ActiveRecord::Base.connection.schema_cache.data_sources("posts")
end
test "expire schema cache dump" do
- Dir.chdir(app_path) do
- `rails generate model post title:string;
- bin/rails db:migrate db:schema:cache:dump db:rollback`
- end
- silence_warnings {
- require "#{app_path}/config/environment"
- assert !ActiveRecord::Base.connection.schema_cache.tables("posts")
- }
+ rails %w(generate model post title:string)
+ rails %w(db:migrate db:schema:cache:dump db:rollback)
+ require "#{app_path}/config/environment"
+ assert_not ActiveRecord::Base.connection.schema_cache.data_sources("posts")
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
+ app_file "config/initializers/active_record.rb", <<-RUBY
+ ActiveRecord::Base.connection
+ RUBY
+ require "#{app_path}/config/environment"
+ assert_not_predicate ActiveRecord::Base.connection_pool, :active_connection?
end
end
end
diff --git a/railties/test/application/initializers/hooks_test.rb b/railties/test/application/initializers/hooks_test.rb
index b2cea0a8e1..1e130c2f9e 100644
--- a/railties/test/application/initializers/hooks_test.rb
+++ b/railties/test/application/initializers/hooks_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "isolation/abstract_unit"
module ApplicationTests
@@ -6,7 +8,6 @@ module ApplicationTests
def setup
build_app
- boot_rails
FileUtils.rm_rf "#{app_path}/config/environments"
end
@@ -32,7 +33,7 @@ module ApplicationTests
RUBY
require "#{app_path}/config/environment"
- assert_equal [1,2,3], $initialization_callbacks
+ assert_equal [1, 2, 3], $initialization_callbacks
end
test "hooks block works correctly with eager_load" do
@@ -47,7 +48,7 @@ module ApplicationTests
RUBY
require "#{app_path}/config/environment"
- assert_equal [1,2,3,4], $initialization_callbacks
+ assert_equal [1, 2, 3, 4], $initialization_callbacks
end
test "after_initialize runs after frameworks have been initialized" do
@@ -58,7 +59,7 @@ module ApplicationTests
require "#{app_path}/config/environment"
assert $activerecord_configurations
- assert $activerecord_configurations['development']
+ assert $activerecord_configurations["development"]
end
test "after_initialize happens after to_prepare in development" do
diff --git a/railties/test/application/initializers/i18n_test.rb b/railties/test/application/initializers/i18n_test.rb
index 0f9bb41053..8058052771 100644
--- a/railties/test/application/initializers/i18n_test.rb
+++ b/railties/test/application/initializers/i18n_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "isolation/abstract_unit"
module ApplicationTests
@@ -6,7 +8,6 @@ module ApplicationTests
def setup
build_app
- boot_rails
FileUtils.rm_rf "#{app_path}/config/environments"
require "rails/all"
end
@@ -31,7 +32,7 @@ module ApplicationTests
end
def assert_no_fallbacks
- assert !I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks)
+ assert_not_includes I18n.backend.class.included_modules, I18n::Backend::Fallbacks
end
# Locales
@@ -63,8 +64,8 @@ module ApplicationTests
"#{app_path}/config/locales/en.yml", "#{app_path}/config/another_locale.yml"
], Rails.application.config.i18n.load_path
- assert I18n.load_path.include?("#{app_path}/config/locales/en.yml")
- assert I18n.load_path.include?("#{app_path}/config/another_locale.yml")
+ assert_includes I18n.load_path, "#{app_path}/config/locales/en.yml"
+ assert_includes I18n.load_path, "#{app_path}/config/another_locale.yml"
end
test "load_path is populated before eager loaded models" do
@@ -77,19 +78,19 @@ en:
foo: "1"
YAML
- app_file 'app/models/foo.rb', <<-RUBY
+ app_file "app/models/foo.rb", <<-RUBY
class Foo < ActiveRecord::Base
@foo = I18n.t(:foo)
end
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get '/i18n', :to => lambda { |env| [200, {}, [Foo.instance_variable_get('@foo')]] }
end
RUBY
- require 'rack/test'
+ require "rack/test"
extend Rack::Test::Methods
load_app
@@ -107,13 +108,13 @@ en:
foo: "1"
YAML
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get '/i18n', :to => lambda { |env| [200, {}, [I18n.t(:foo)]] }
end
RUBY
- require 'rack/test'
+ require "rack/test"
extend Rack::Test::Methods
load_app
@@ -142,13 +143,13 @@ en:
foo: "1"
YAML
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get '/i18n', :to => lambda { |env| [200, {}, [I18n.t(:foo)]] }
end
RUBY
- require 'rack/test'
+ require "rack/test"
extend Rack::Test::Methods
load_app
@@ -178,13 +179,13 @@ en:
foo: "1"
YAML
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get '/i18n', :to => lambda { |env| [200, {}, [I18n.load_path.inspect]] }
end
RUBY
- require 'rack/test'
+ require "rack/test"
extend Rack::Test::Methods
load_app
@@ -215,7 +216,7 @@ fr:
test "config.i18n.fallbacks = true initializes I18n.fallbacks with default settings" do
I18n::Railtie.config.i18n.fallbacks = true
load_app
- assert I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks)
+ assert_includes I18n.backend.class.included_modules, I18n::Backend::Fallbacks
assert_fallbacks de: [:de, :en]
end
@@ -223,7 +224,7 @@ fr:
I18n::Railtie.config.i18n.fallbacks = true
I18n::Railtie.config.i18n.backend = Class.new(I18n::Backend::Simple).new
load_app
- assert I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks)
+ assert_includes I18n.backend.class.included_modules, I18n::Backend::Fallbacks
assert_fallbacks de: [:de, :en]
end
@@ -234,7 +235,7 @@ fr:
end
test "config.i18n.fallbacks.map = { :ca => :'es-ES' } initializes fallbacks with a mapping ca => es-ES" do
- I18n::Railtie.config.i18n.fallbacks.map = { :ca => :'es-ES' }
+ I18n::Railtie.config.i18n.fallbacks.map = { ca: :'es-ES' }
load_app
assert_fallbacks ca: [:ca, :"es-ES", :es, :en]
end
@@ -246,13 +247,13 @@ fr:
end
test "[shortcut] config.i18n.fallbacks = [{ :ca => :'es-ES' }] initializes fallbacks with a mapping ca => es-ES" do
- I18n::Railtie.config.i18n.fallbacks.map = { :ca => :'es-ES' }
+ I18n::Railtie.config.i18n.fallbacks = [{ ca: :'es-ES' }]
load_app
assert_fallbacks ca: [:ca, :"es-ES", :es, :en]
end
test "[shortcut] config.i18n.fallbacks = [:'en-US', { :ca => :'es-ES' }] initializes fallbacks with the given arguments" do
- I18n::Railtie.config.i18n.fallbacks = [:'en-US', { :ca => :'es-ES' }]
+ I18n::Railtie.config.i18n.fallbacks = [:'en-US', { ca: :'es-ES' }]
load_app
assert_fallbacks ca: [:ca, :"es-ES", :es, :'en-US', :en]
end
diff --git a/railties/test/application/initializers/load_path_test.rb b/railties/test/application/initializers/load_path_test.rb
index cd05956356..78cd4776d6 100644
--- a/railties/test/application/initializers/load_path_test.rb
+++ b/railties/test/application/initializers/load_path_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "isolation/abstract_unit"
module ApplicationTests
@@ -6,7 +8,6 @@ module ApplicationTests
def setup
build_app
- boot_rails
FileUtils.rm_rf "#{app_path}/config/environments"
end
@@ -20,7 +21,7 @@ module ApplicationTests
RUBY
require "#{app_path}/config/environment"
- assert $:.include?("#{app_path}/app/models")
+ assert_includes $:, "#{app_path}/app/models"
end
test "initializing an application allows to load code on lib path inside application class definition" do
@@ -37,7 +38,7 @@ module ApplicationTests
require "#{app_path}/config/environment"
end
- assert $:.include?("#{app_path}/lib")
+ assert_includes $:, "#{app_path}/lib"
end
test "initializing an application eager load any path under app" do
diff --git a/railties/test/application/initializers/notifications_test.rb b/railties/test/application/initializers/notifications_test.rb
index 95655b74cf..c65c955734 100644
--- a/railties/test/application/initializers/notifications_test.rb
+++ b/railties/test/application/initializers/notifications_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "isolation/abstract_unit"
module ApplicationTests
@@ -6,7 +8,6 @@ module ApplicationTests
def setup
build_app
- boot_rails
end
def teardown
@@ -31,6 +32,7 @@ module ApplicationTests
logger = ActiveSupport::LogSubscriber::TestHelper::MockLogger.new
ActiveRecord::Base.logger = logger
+ ActiveRecord::Base.verbose_query_logs = false
# Mimic Active Record notifications
instrument "sql.active_record", name: "SQL", sql: "SHOW tables"
@@ -40,17 +42,17 @@ module ApplicationTests
assert_match(/SHOW tables/, logger.logged(:debug).last)
end
- test 'rails load_config_initializer event is instrumented' do
- app_file 'config/initializers/foo.rb', ''
+ test "rails load_config_initializer event is instrumented" do
+ app_file "config/initializers/foo.rb", ""
events = []
callback = ->(*_) { events << _ }
- ActiveSupport::Notifications.subscribed(callback, 'load_config_initializer.railties') do
+ ActiveSupport::Notifications.subscribed(callback, "load_config_initializer.railties") do
app
end
assert_equal %w[load_config_initializer.railties], events.map(&:first)
- assert_includes events.first.last[:initializer], 'config/initializers/foo.rb'
+ assert_includes events.first.last[:initializer], "config/initializers/foo.rb"
end
end
end
diff --git a/railties/test/application/integration_test_case_test.rb b/railties/test/application/integration_test_case_test.rb
index d106d5159a..c08761092b 100644
--- a/railties/test/application/integration_test_case_test.rb
+++ b/railties/test/application/integration_test_case_test.rb
@@ -1,12 +1,14 @@
-require 'isolation/abstract_unit'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "env_helpers"
module ApplicationTests
class IntegrationTestCaseTest < ActiveSupport::TestCase
- include ActiveSupport::Testing::Isolation
+ include ActiveSupport::Testing::Isolation, EnvHelpers
setup do
build_app
- boot_rails
end
teardown do
@@ -14,9 +16,9 @@ module ApplicationTests
end
test "resets Action Mailer test deliveries" do
- script('generate mailer BaseMailer welcome')
+ rails "generate", "mailer", "BaseMailer", "welcome"
- app_file 'test/integration/mailer_integration_test.rb', <<-RUBY
+ app_file "test/integration/mailer_integration_test.rb", <<-RUBY
require 'test_helper'
class MailerIntegrationTest < ActionDispatch::IntegrationTest
@@ -38,8 +40,36 @@ module ApplicationTests
end
RUBY
- output = Dir.chdir(app_path) { `bin/rails test 2>&1` }
- assert_equal 0, $?.to_i, output
+ with_rails_env("test") { rails("db:migrate") }
+ output = rails("test")
+ assert_match(/0 failures, 0 errors/, output)
+ end
+ end
+
+ class IntegrationTestDefaultApp < ActiveSupport::TestCase
+ include ActiveSupport::Testing::Isolation, EnvHelpers
+
+ setup do
+ build_app
+ end
+
+ teardown do
+ teardown_app
+ end
+
+ test "app method of integration tests returns test_app by default" do
+ app_file "test/integration/default_app_test.rb", <<-RUBY
+ require 'test_helper'
+
+ class DefaultAppIntegrationTest < ActionDispatch::IntegrationTest
+ def test_app_returns_action_dispatch_test_app_by_default
+ assert_equal ActionDispatch.test_app, app
+ end
+ end
+ RUBY
+
+ with_rails_env("test") { rails("db:migrate") }
+ output = rails("test")
assert_match(/0 failures, 0 errors/, output)
end
end
diff --git a/railties/test/application/loading_test.rb b/railties/test/application/loading_test.rb
index efb21ae473..9c98489590 100644
--- a/railties/test/application/loading_test.rb
+++ b/railties/test/application/loading_test.rb
@@ -1,11 +1,12 @@
-require 'isolation/abstract_unit'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
class LoadingTest < ActiveSupport::TestCase
include ActiveSupport::Testing::Isolation
def setup
build_app
- boot_rails
end
def teardown
@@ -26,11 +27,27 @@ class LoadingTest < ActiveSupport::TestCase
require "#{rails_root}/config/environment"
setup_ar!
- p = Post.create(title: 'omg')
+ p = Post.create(title: "omg")
assert_equal 1, Post.count
- assert_equal 'omg', p.title
+ assert_equal "omg", p.title
p = Post.first
- assert_equal 'omg', p.title
+ 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
@@ -103,24 +120,24 @@ class LoadingTest < ActiveSupport::TestCase
end
MODEL
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get '/load', to: lambda { |env| [200, {}, Post.all] }
get '/unload', to: lambda { |env| [200, {}, []] }
end
RUBY
- require 'rack/test'
+ require "rack/test"
extend Rack::Test::Methods
require "#{rails_root}/config/environment"
setup_ar!
- assert_equal [ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata], ActiveRecord::Base.descendants
+ assert_equal [ActiveStorage::Blob, ActiveStorage::Attachment, ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata].collect(&:to_s).sort, ActiveRecord::Base.descendants.collect(&:to_s).sort
get "/load"
- assert_equal [ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata, Post], ActiveRecord::Base.descendants
+ assert_equal [ActiveStorage::Blob, ActiveStorage::Attachment, ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata, Post].collect(&:to_s).sort, ActiveRecord::Base.descendants.collect(&:to_s).sort
get "/unload"
- assert_equal [ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata], ActiveRecord::Base.descendants
+ assert_equal [ActiveStorage::Blob, ActiveStorage::Attachment, ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata].collect(&:to_s).sort, ActiveRecord::Base.descendants.collect(&:to_s).sort
end
test "initialize cant be called twice" do
@@ -133,7 +150,7 @@ class LoadingTest < ActiveSupport::TestCase
config.cache_classes = false
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get '/c', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [User.counter.to_s]] }
end
@@ -145,7 +162,7 @@ class LoadingTest < ActiveSupport::TestCase
end
MODEL
- require 'rack/test'
+ require "rack/test"
extend Rack::Test::Methods
require "#{rails_root}/config/environment"
@@ -174,7 +191,7 @@ class LoadingTest < ActiveSupport::TestCase
end
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get '/c', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [User.counter.to_s]] }
end
@@ -186,7 +203,7 @@ class LoadingTest < ActiveSupport::TestCase
end
MODEL
- require 'rack/test'
+ require "rack/test"
extend Rack::Test::Methods
require "#{rails_root}/config/environment"
@@ -209,7 +226,7 @@ class LoadingTest < ActiveSupport::TestCase
config.cache_classes = false
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
$counter ||= 0
Rails.application.routes.draw do
get '/c', to: lambda { |env| User.name; [200, {"Content-Type" => "text/plain"}, [$counter.to_s]] }
@@ -222,7 +239,7 @@ class LoadingTest < ActiveSupport::TestCase
end
MODEL
- require 'rack/test'
+ require "rack/test"
extend Rack::Test::Methods
require "#{rails_root}/config/environment"
@@ -241,7 +258,7 @@ class LoadingTest < ActiveSupport::TestCase
config.cache_classes = false
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
$counter ||= 1
$counter *= 2
Rails.application.routes.draw do
@@ -255,7 +272,7 @@ class LoadingTest < ActiveSupport::TestCase
end
MODEL
- require 'rack/test'
+ require "rack/test"
extend Rack::Test::Methods
require "#{rails_root}/config/environment"
@@ -274,7 +291,7 @@ class LoadingTest < ActiveSupport::TestCase
config.cache_classes = false
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get '/title', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [Post.new.title]] }
get '/body', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [Post.new.body]] }
@@ -286,7 +303,7 @@ class LoadingTest < ActiveSupport::TestCase
end
MODEL
- require 'rack/test'
+ require "rack/test"
extend Rack::Test::Methods
app_file "db/migrate/1_create_posts.rb", <<-MIGRATION
@@ -299,7 +316,7 @@ class LoadingTest < ActiveSupport::TestCase
end
MIGRATION
- Dir.chdir(app_path) { `rake db:migrate`}
+ rails("db:migrate")
require "#{rails_root}/config/environment"
get "/title"
@@ -313,7 +330,7 @@ class LoadingTest < ActiveSupport::TestCase
end
MIGRATION
- Dir.chdir(app_path) { `rake db:migrate` }
+ rails("db:migrate")
get "/body"
assert_equal "BODY", last_response.body
@@ -341,32 +358,118 @@ class LoadingTest < ActiveSupport::TestCase
require "#{rails_root}/config/environment"
- require 'rack/test'
+ require "rack/test"
extend Rack::Test::Methods
- get '/omg/show'
- assert_equal 'OK', last_response.body
+ get "/omg/show"
+ assert_equal "OK", last_response.body
end
def test_initialize_can_be_called_at_any_time
require "#{app_path}/config/application"
- assert !Rails.initialized?
- assert !Rails.application.initialized?
+ assert_not_predicate Rails, :initialized?
+ assert_not_predicate Rails.application, :initialized?
Rails.initialize!
- assert Rails.initialized?
- assert Rails.application.initialized?
+ assert_predicate Rails, :initialized?
+ assert_predicate Rails.application, :initialized?
end
- protected
-
- def setup_ar!
- 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
+ test "frameworks aren't loaded during initialization" do
+ app_file "config/initializers/raise_when_frameworks_load.rb", <<-RUBY
+ %i(action_controller action_mailer active_job active_record).each do |framework|
+ ActiveSupport.on_load(framework) { raise "\#{framework} loaded!" }
end
+ RUBY
+
+ assert_nothing_raised do
+ require "#{app_path}/config/environment"
end
end
+
+ test "active record query cache hooks are installed before first request in production" do
+ app_file "app/controllers/omg_controller.rb", <<-RUBY
+ begin
+ class OmgController < ActionController::Metal
+ ActiveSupport.run_load_hooks(:action_controller, self)
+ def show
+ if ActiveRecord::Base.connection.query_cache_enabled
+ self.response_body = ["Query cache is enabled."]
+ else
+ self.response_body = ["Expected ActiveRecord::Base.connection.query_cache_enabled to be true"]
+ end
+ end
+ end
+ rescue => e
+ puts "Error loading metal: \#{e.class} \#{e.message}"
+ end
+ RUBY
+
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ get "/:controller(/:action)"
+ end
+ RUBY
+
+ boot_app "production"
+
+ require "rack/test"
+ extend Rack::Test::Methods
+
+ get "/omg/show"
+ assert_equal "Query cache is enabled.", last_response.body
+ end
+
+ test "active record query cache hooks are installed before first request in development" do
+ app_file "app/controllers/omg_controller.rb", <<-RUBY
+ begin
+ class OmgController < ActionController::Metal
+ ActiveSupport.run_load_hooks(:action_controller, self)
+ def show
+ if ActiveRecord::Base.connection.query_cache_enabled
+ self.response_body = ["Query cache is enabled."]
+ else
+ self.response_body = ["Expected ActiveRecord::Base.connection.query_cache_enabled to be true"]
+ end
+ end
+ end
+ rescue => e
+ puts "Error loading metal: \#{e.class} \#{e.message}"
+ end
+ RUBY
+
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ get "/:controller(/:action)"
+ end
+ RUBY
+
+ boot_app "development"
+
+ require "rack/test"
+ extend Rack::Test::Methods
+
+ get "/omg/show"
+ assert_equal "Query cache is enabled.", last_response.body
+ end
+
+ private
+
+ def setup_ar!
+ 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
+ end
+
+ def boot_app(env = "development")
+ ENV["RAILS_ENV"] = env
+
+ require "#{app_path}/config/environment"
+ ensure
+ ENV.delete "RAILS_ENV"
+ end
end
diff --git a/railties/test/application/mailer_previews_test.rb b/railties/test/application/mailer_previews_test.rb
index 643d876a26..fb84276b8a 100644
--- a/railties/test/application/mailer_previews_test.rb
+++ b/railties/test/application/mailer_previews_test.rb
@@ -1,6 +1,8 @@
-require 'isolation/abstract_unit'
-require 'rack/test'
-require 'base64'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "rack/test"
+require "base64"
module ApplicationTests
class MailerPreviewsTest < ActiveSupport::TestCase
@@ -9,7 +11,6 @@ module ApplicationTests
def setup
build_app
- boot_rails
end
def teardown
@@ -28,10 +29,10 @@ module ApplicationTests
assert_equal 404, last_response.status
end
- test "/rails/mailers is accessible with correct configuraiton" do
+ test "/rails/mailers is accessible with correct configuration" do
add_to_config "config.action_mailer.show_previews = true"
app("production")
- get "/rails/mailers", {}, {"REMOTE_ADDR" => "4.2.42.42"}
+ get "/rails/mailers", {}, { "REMOTE_ADDR" => "4.2.42.42" }
assert_equal 200, last_response.status
end
@@ -54,7 +55,7 @@ module ApplicationTests
end
test "mailer previews are loaded from the default preview_path" do
- mailer 'notifier', <<-RUBY
+ mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
default from: "from@example.com"
@@ -64,11 +65,11 @@ module ApplicationTests
end
RUBY
- text_template 'notifier/foo', <<-RUBY
+ text_template "notifier/foo", <<-RUBY
Hello, World!
RUBY
- mailer_preview 'notifier', <<-RUBY
+ mailer_preview "notifier", <<-RUBY
class NotifierPreview < ActionMailer::Preview
def foo
Notifier.foo
@@ -76,7 +77,7 @@ module ApplicationTests
end
RUBY
- app('development')
+ app("development")
get "/rails/mailers"
assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body
@@ -84,9 +85,10 @@ 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
+ mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
default from: "from@example.com"
@@ -96,11 +98,11 @@ module ApplicationTests
end
RUBY
- text_template 'notifier/foo', <<-RUBY
+ text_template "notifier/foo", <<-RUBY
Hello, World!
RUBY
- app_file 'lib/mailer_previews/notifier_preview.rb', <<-RUBY
+ app_file "lib/mailer_previews/notifier_preview.rb", <<-RUBY
class NotifierPreview < ActionMailer::Preview
def foo
Notifier.foo
@@ -108,7 +110,7 @@ module ApplicationTests
end
RUBY
- app('development')
+ app("development")
get "/rails/mailers"
assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body
@@ -116,12 +118,12 @@ module ApplicationTests
end
test "mailer previews are reloaded across requests" do
- app('development')
+ app("development")
get "/rails/mailers"
assert_no_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body
- mailer 'notifier', <<-RUBY
+ mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
default from: "from@example.com"
@@ -131,11 +133,11 @@ module ApplicationTests
end
RUBY
- text_template 'notifier/foo', <<-RUBY
+ text_template "notifier/foo", <<-RUBY
Hello, World!
RUBY
- mailer_preview 'notifier', <<-RUBY
+ mailer_preview "notifier", <<-RUBY
class NotifierPreview < ActionMailer::Preview
def foo
Notifier.foo
@@ -146,7 +148,7 @@ module ApplicationTests
get "/rails/mailers"
assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body
- remove_file 'test/mailers/previews/notifier_preview.rb'
+ remove_file "test/mailers/previews/notifier_preview.rb"
sleep(1)
get "/rails/mailers"
@@ -154,7 +156,7 @@ module ApplicationTests
end
test "mailer preview actions are added and removed" do
- mailer 'notifier', <<-RUBY
+ mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
default from: "from@example.com"
@@ -164,11 +166,11 @@ module ApplicationTests
end
RUBY
- text_template 'notifier/foo', <<-RUBY
+ text_template "notifier/foo", <<-RUBY
Hello, World!
RUBY
- mailer_preview 'notifier', <<-RUBY
+ mailer_preview "notifier", <<-RUBY
class NotifierPreview < ActionMailer::Preview
def foo
Notifier.foo
@@ -176,14 +178,14 @@ module ApplicationTests
end
RUBY
- app('development')
+ app("development")
get "/rails/mailers"
assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body
assert_match '<li><a href="/rails/mailers/notifier/foo">foo</a></li>', last_response.body
assert_no_match '<li><a href="/rails/mailers/notifier/bar">bar</a></li>', last_response.body
- mailer 'notifier', <<-RUBY
+ mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
default from: "from@example.com"
@@ -197,15 +199,15 @@ module ApplicationTests
end
RUBY
- text_template 'notifier/foo', <<-RUBY
+ text_template "notifier/foo", <<-RUBY
Hello, World!
RUBY
- text_template 'notifier/bar', <<-RUBY
+ text_template "notifier/bar", <<-RUBY
Goodbye, World!
RUBY
- mailer_preview 'notifier', <<-RUBY
+ mailer_preview "notifier", <<-RUBY
class NotifierPreview < ActionMailer::Preview
def foo
Notifier.foo
@@ -224,7 +226,7 @@ module ApplicationTests
assert_match '<li><a href="/rails/mailers/notifier/foo">foo</a></li>', last_response.body
assert_match '<li><a href="/rails/mailers/notifier/bar">bar</a></li>', last_response.body
- mailer 'notifier', <<-RUBY
+ mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
default from: "from@example.com"
@@ -234,9 +236,9 @@ module ApplicationTests
end
RUBY
- remove_file 'app/views/notifier/bar.text.erb'
+ remove_file "app/views/notifier/bar.text.erb"
- mailer_preview 'notifier', <<-RUBY
+ mailer_preview "notifier", <<-RUBY
class NotifierPreview < ActionMailer::Preview
def foo
Notifier.foo
@@ -253,14 +255,15 @@ 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')
+ app("development")
get "/rails/mailers"
assert_no_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body
- mailer 'notifier', <<-RUBY
+ mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
default from: "from@example.com"
@@ -270,11 +273,11 @@ module ApplicationTests
end
RUBY
- text_template 'notifier/foo', <<-RUBY
+ text_template "notifier/foo", <<-RUBY
Hello, World!
RUBY
- app_file 'lib/mailer_previews/notifier_preview.rb', <<-RUBY
+ app_file "lib/mailer_previews/notifier_preview.rb", <<-RUBY
class NotifierPreview < ActionMailer::Preview
def foo
Notifier.foo
@@ -285,7 +288,7 @@ module ApplicationTests
get "/rails/mailers"
assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body
- remove_file 'lib/mailer_previews/notifier_preview.rb'
+ remove_file "lib/mailer_previews/notifier_preview.rb"
sleep(1)
get "/rails/mailers"
@@ -293,14 +296,14 @@ module ApplicationTests
end
test "mailer preview not found" do
- app('development')
+ app("development")
get "/rails/mailers/notifier"
- assert last_response.not_found?
+ assert_predicate last_response, :not_found?
assert_match "Mailer preview &#39;notifier&#39; not found", last_response.body
end
test "mailer preview email not found" do
- mailer 'notifier', <<-RUBY
+ mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
default from: "from@example.com"
@@ -310,11 +313,11 @@ module ApplicationTests
end
RUBY
- text_template 'notifier/foo', <<-RUBY
+ text_template "notifier/foo", <<-RUBY
Hello, World!
RUBY
- mailer_preview 'notifier', <<-RUBY
+ mailer_preview "notifier", <<-RUBY
class NotifierPreview < ActionMailer::Preview
def foo
Notifier.foo
@@ -322,15 +325,15 @@ module ApplicationTests
end
RUBY
- app('development')
+ app("development")
get "/rails/mailers/notifier/bar"
- assert last_response.not_found?
+ assert_predicate last_response, :not_found?
assert_match "Email &#39;bar&#39; not found in NotifierPreview", last_response.body
end
test "mailer preview NullMail" do
- mailer 'notifier', <<-RUBY
+ mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
default from: "from@example.com"
@@ -340,7 +343,7 @@ module ApplicationTests
end
RUBY
- mailer_preview 'notifier', <<-RUBY
+ mailer_preview "notifier", <<-RUBY
class NotifierPreview < ActionMailer::Preview
def foo
Notifier.foo
@@ -348,7 +351,7 @@ module ApplicationTests
end
RUBY
- app('development')
+ app("development")
get "/rails/mailers/notifier/foo"
assert_match "You are trying to preview an email that does not have any content.", last_response.body
@@ -356,7 +359,7 @@ module ApplicationTests
end
test "mailer preview email part not found" do
- mailer 'notifier', <<-RUBY
+ mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
default from: "from@example.com"
@@ -366,11 +369,11 @@ module ApplicationTests
end
RUBY
- text_template 'notifier/foo', <<-RUBY
+ text_template "notifier/foo", <<-RUBY
Hello, World!
RUBY
- mailer_preview 'notifier', <<-RUBY
+ mailer_preview "notifier", <<-RUBY
class NotifierPreview < ActionMailer::Preview
def foo
Notifier.foo
@@ -378,15 +381,15 @@ module ApplicationTests
end
RUBY
- app('development')
+ app("development")
get "/rails/mailers/notifier/foo?part=text%2Fhtml"
- assert last_response.not_found?
+ assert_predicate last_response, :not_found?
assert_match "Email part &#39;text/html&#39; not found in NotifierPreview#foo", last_response.body
end
test "message header uses full display names" do
- mailer 'notifier', <<-RUBY
+ mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
default from: "Ruby on Rails <core@rubyonrails.org>"
@@ -397,11 +400,11 @@ module ApplicationTests
end
RUBY
- text_template 'notifier/foo', <<-RUBY
+ text_template "notifier/foo", <<-RUBY
Hello, World!
RUBY
- mailer_preview 'notifier', <<-RUBY
+ mailer_preview "notifier", <<-RUBY
class NotifierPreview < ActionMailer::Preview
def foo
Notifier.foo
@@ -409,7 +412,7 @@ module ApplicationTests
end
RUBY
- app('development')
+ app("development")
get "/rails/mailers/notifier/foo"
assert_equal 200, last_response.status
@@ -419,7 +422,51 @@ module ApplicationTests
end
test "part menu selects correct option" do
- mailer 'notifier', <<-RUBY
+ mailer "notifier", <<-RUBY
+ class Notifier < ActionMailer::Base
+ default from: "from@example.com"
+
+ def foo
+ mail to: "to@example.org"
+ end
+ end
+ RUBY
+
+ html_template "notifier/foo", <<-RUBY
+ <p>Hello, World!</p>
+ RUBY
+
+ text_template "notifier/foo", <<-RUBY
+ Hello, World!
+ RUBY
+
+ mailer_preview "notifier", <<-RUBY
+ class NotifierPreview < ActionMailer::Preview
+ def foo
+ Notifier.foo
+ end
+ end
+ RUBY
+
+ app("development")
+
+ get "/rails/mailers/notifier/foo.html"
+ assert_equal 200, last_response.status
+ assert_match '<option selected value="part=text%2Fhtml">View as HTML email</option>', last_response.body
+
+ get "/rails/mailers/notifier/foo.txt"
+ assert_equal 200, last_response.status
+ assert_match '<option selected value="part=text%2Fplain">View as plain-text email</option>', last_response.body
+ end
+
+ test "locale menu selects correct option" do
+ app_file "config/initializers/available_locales.rb", <<-RUBY
+ Rails.application.configure do
+ config.i18n.available_locales = %i[en ja]
+ end
+ RUBY
+
+ mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
default from: "from@example.com"
@@ -429,15 +476,15 @@ module ApplicationTests
end
RUBY
- html_template 'notifier/foo', <<-RUBY
+ html_template "notifier/foo", <<-RUBY
<p>Hello, World!</p>
RUBY
- text_template 'notifier/foo', <<-RUBY
+ text_template "notifier/foo", <<-RUBY
Hello, World!
RUBY
- mailer_preview 'notifier', <<-RUBY
+ mailer_preview "notifier", <<-RUBY
class NotifierPreview < ActionMailer::Preview
def foo
Notifier.foo
@@ -445,19 +492,31 @@ module ApplicationTests
end
RUBY
- app('development')
+ app("development")
get "/rails/mailers/notifier/foo.html"
assert_equal 200, last_response.status
- assert_match '<option selected value="?part=text%2Fhtml">View as HTML email</option>', last_response.body
+ assert_match '<option selected value="locale=en">en', last_response.body
+ assert_match '<option value="locale=ja">ja', last_response.body
+
+ get "/rails/mailers/notifier/foo.html?locale=ja"
+ assert_equal 200, last_response.status
+ assert_match '<option value="locale=en">en', last_response.body
+ assert_match '<option selected value="locale=ja">ja', last_response.body
get "/rails/mailers/notifier/foo.txt"
assert_equal 200, last_response.status
- assert_match '<option selected value="?part=text%2Fplain">View as plain-text email</option>', last_response.body
+ assert_match '<option selected value="locale=en">en', last_response.body
+ assert_match '<option value="locale=ja">ja', last_response.body
+
+ get "/rails/mailers/notifier/foo.txt?locale=ja"
+ assert_equal 200, last_response.status
+ assert_match '<option value="locale=en">en', last_response.body
+ assert_match '<option selected value="locale=ja">ja', last_response.body
end
test "mailer previews create correct links when loaded on a subdirectory" do
- mailer 'notifier', <<-RUBY
+ mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
default from: "from@example.com"
@@ -467,11 +526,11 @@ module ApplicationTests
end
RUBY
- text_template 'notifier/foo', <<-RUBY
+ text_template "notifier/foo", <<-RUBY
Hello, World!
RUBY
- mailer_preview 'notifier', <<-RUBY
+ mailer_preview "notifier", <<-RUBY
class NotifierPreview < ActionMailer::Preview
def foo
Notifier.foo
@@ -479,17 +538,68 @@ module ApplicationTests
end
RUBY
- app('development')
+ app("development")
- get "/rails/mailers", {}, 'SCRIPT_NAME' => '/my_app'
+ get "/rails/mailers", {}, { "SCRIPT_NAME" => "/my_app" }
assert_match '<h3><a href="/my_app/rails/mailers/notifier">Notifier</a></h3>', last_response.body
assert_match '<li><a href="/my_app/rails/mailers/notifier/foo">foo</a></li>', last_response.body
end
+ test "mailer preview receives query params" do
+ mailer "notifier", <<-RUBY
+ class Notifier < ActionMailer::Base
+ default from: "from@example.com"
+
+ def foo(name)
+ @name = name
+ mail to: "to@example.org"
+ end
+ end
+ RUBY
+
+ html_template "notifier/foo", <<-RUBY
+ <p>Hello, <%= @name %>!</p>
+ RUBY
+
+ text_template "notifier/foo", <<-RUBY
+ Hello, <%= @name %>!
+ RUBY
+
+ mailer_preview "notifier", <<-RUBY
+ class NotifierPreview < ActionMailer::Preview
+ def foo
+ Notifier.foo(params[:name] || "World")
+ end
+ end
+ RUBY
+
+ app("development")
+
+ get "/rails/mailers/notifier/foo.txt"
+ assert_equal 200, last_response.status
+ assert_match '<iframe seamless name="messageBody" src="?part=text%2Fplain">', last_response.body
+ assert_match '<option selected value="part=text%2Fplain">', last_response.body
+ assert_match '<option value="part=text%2Fhtml">', last_response.body
+
+ get "/rails/mailers/notifier/foo?part=text%2Fplain"
+ assert_equal 200, last_response.status
+ assert_match %r[Hello, World!], last_response.body
+
+ get "/rails/mailers/notifier/foo.html?name=Ruby"
+ assert_equal 200, last_response.status
+ assert_match '<iframe seamless name="messageBody" src="?name=Ruby&amp;part=text%2Fhtml">', last_response.body
+ assert_match '<option selected value="name=Ruby&amp;part=text%2Fhtml">', last_response.body
+ assert_match '<option value="name=Ruby&amp;part=text%2Fplain">', last_response.body
+
+ get "/rails/mailers/notifier/foo?name=Ruby&part=text%2Fhtml"
+ assert_equal 200, last_response.status
+ assert_match %r[<p>Hello, Ruby!</p>], last_response.body
+ end
+
test "plain text mailer preview with attachment" do
image_file "pixel.png", "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEWzIioca/JlAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJgggo="
- mailer 'notifier', <<-RUBY
+ mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
default from: "from@example.com"
@@ -500,11 +610,11 @@ module ApplicationTests
end
RUBY
- text_template 'notifier/foo', <<-RUBY
+ text_template "notifier/foo", <<-RUBY
Hello, World!
RUBY
- mailer_preview 'notifier', <<-RUBY
+ mailer_preview "notifier", <<-RUBY
class NotifierPreview < ActionMailer::Preview
def foo
Notifier.foo
@@ -512,7 +622,7 @@ module ApplicationTests
end
RUBY
- app('development')
+ app("development")
get "/rails/mailers/notifier/foo"
assert_equal 200, last_response.status
@@ -526,7 +636,7 @@ module ApplicationTests
test "multipart mailer preview with attachment" do
image_file "pixel.png", "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEWzIioca/JlAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJgggo="
- mailer 'notifier', <<-RUBY
+ mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
default from: "from@example.com"
@@ -537,15 +647,15 @@ module ApplicationTests
end
RUBY
- text_template 'notifier/foo', <<-RUBY
+ text_template "notifier/foo", <<-RUBY
Hello, World!
RUBY
- html_template 'notifier/foo', <<-RUBY
+ html_template "notifier/foo", <<-RUBY
<p>Hello, World!</p>
RUBY
- mailer_preview 'notifier', <<-RUBY
+ mailer_preview "notifier", <<-RUBY
class NotifierPreview < ActionMailer::Preview
def foo
Notifier.foo
@@ -553,7 +663,7 @@ module ApplicationTests
end
RUBY
- app('development')
+ app("development")
get "/rails/mailers/notifier/foo"
assert_equal 200, last_response.status
@@ -571,7 +681,7 @@ module ApplicationTests
test "multipart mailer preview with inline attachment" do
image_file "pixel.png", "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEWzIioca/JlAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJgggo="
- mailer 'notifier', <<-RUBY
+ mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
default from: "from@example.com"
@@ -582,16 +692,16 @@ module ApplicationTests
end
RUBY
- text_template 'notifier/foo', <<-RUBY
+ text_template "notifier/foo", <<-RUBY
Hello, World!
RUBY
- html_template 'notifier/foo', <<-RUBY
+ html_template "notifier/foo", <<-RUBY
<p>Hello, World!</p>
<%= image_tag attachments['pixel.png'].url %>
RUBY
- mailer_preview 'notifier', <<-RUBY
+ mailer_preview "notifier", <<-RUBY
class NotifierPreview < ActionMailer::Preview
def foo
Notifier.foo
@@ -599,7 +709,7 @@ module ApplicationTests
end
RUBY
- app('development')
+ app("development")
get "/rails/mailers/notifier/foo"
assert_equal 200, last_response.status
@@ -616,7 +726,7 @@ module ApplicationTests
end
test "multipart mailer preview with attached email" do
- mailer 'notifier', <<-RUBY
+ mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
default from: "from@example.com"
@@ -641,15 +751,15 @@ module ApplicationTests
end
RUBY
- text_template 'notifier/foo', <<-RUBY
+ text_template "notifier/foo", <<-RUBY
Hello, World!
RUBY
- html_template 'notifier/foo', <<-RUBY
+ html_template "notifier/foo", <<-RUBY
<p>Hello, World!</p>
RUBY
- mailer_preview 'notifier', <<-RUBY
+ mailer_preview "notifier", <<-RUBY
class NotifierPreview < ActionMailer::Preview
def foo
Notifier.foo
@@ -657,7 +767,7 @@ module ApplicationTests
end
RUBY
- app('development')
+ app("development")
get "/rails/mailers/notifier/foo"
assert_equal 200, last_response.status
@@ -672,10 +782,45 @@ module ApplicationTests
assert_match %r[<p>Hello, World!</p>], last_response.body
end
+ test "multipart mailer preview with empty parts" do
+ mailer "notifier", <<-RUBY
+ class Notifier < ActionMailer::Base
+ default from: "from@example.com"
+
+ def foo
+ mail to: "to@example.org"
+ end
+ end
+ RUBY
+
+ text_template "notifier/foo", <<-RUBY
+ RUBY
+
+ html_template "notifier/foo", <<-RUBY
+ RUBY
+
+ mailer_preview "notifier", <<-RUBY
+ class NotifierPreview < ActionMailer::Preview
+ def foo
+ Notifier.foo
+ end
+ end
+ RUBY
+
+ app("development")
+
+ get "/rails/mailers/notifier/foo?part=text/plain"
+ assert_equal 200, last_response.status
+
+ get "/rails/mailers/notifier/foo?part=text/html"
+ assert_equal 200, last_response.status
+ end
+
private
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)
@@ -695,7 +840,7 @@ module ApplicationTests
end
def image_file(name, contents)
- app_file("public/images/#{name}", Base64.strict_decode64(contents), 'wb')
+ app_file("public/images/#{name}", Base64.strict_decode64(contents), "wb")
end
end
end
diff --git a/railties/test/application/middleware/cache_test.rb b/railties/test/application/middleware/cache_test.rb
index c951dabd6c..3768d8ce2d 100644
--- a/railties/test/application/middleware/cache_test.rb
+++ b/railties/test/application/middleware/cache_test.rb
@@ -1,4 +1,6 @@
-require 'isolation/abstract_unit'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
module ApplicationTests
class CacheTest < ActiveSupport::TestCase
@@ -6,8 +8,7 @@ module ApplicationTests
def setup
build_app
- boot_rails
- require 'rack/test'
+ require "rack/test"
extend Rack::Test::Methods
end
@@ -20,7 +21,7 @@ module ApplicationTests
class ExpiresController < ApplicationController
def expires_header
expires_in 10, public: !params[:private]
- render text: SecureRandom.hex(16)
+ render plain: SecureRandom.hex(16)
end
def expires_etag
@@ -33,18 +34,18 @@ module ApplicationTests
end
def keeps_if_modified_since
- render :text => request.headers['If-Modified-Since']
+ render plain: request.headers['If-Modified-Since']
end
private
def render_conditionally(headers)
if stale?(headers.merge(public: !params[:private]))
- render text: SecureRandom.hex(16)
+ render plain: SecureRandom.hex(16)
end
end
end
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get ':controller(/:action)'
end
@@ -55,7 +56,7 @@ module ApplicationTests
simple_controller
expected = "Wed, 30 May 1984 19:43:31 GMT"
- get "/expires/keeps_if_modified_since", {}, "HTTP_IF_MODIFIED_SINCE" => expected
+ get "/expires/keeps_if_modified_since", {}, { "HTTP_IF_MODIFIED_SINCE" => expected }
assert_equal 200, last_response.status
assert_equal expected, last_response.body, "cache should have kept If-Modified-Since"
@@ -66,12 +67,12 @@ module ApplicationTests
app("development")
get "/expires/expires_header"
- assert_nil last_response.headers['X-Rack-Cache']
+ assert_nil last_response.headers["X-Rack-Cache"]
body = last_response.body
get "/expires/expires_header"
- assert_nil last_response.headers['X-Rack-Cache']
+ assert_nil last_response.headers["X-Rack-Cache"]
assert_not_equal body, last_response.body
end
@@ -118,12 +119,12 @@ module ApplicationTests
assert_equal "miss, store", last_response.headers["X-Rack-Cache"]
assert_equal "public", last_response.headers["Cache-Control"]
- body = last_response.body
etag = last_response.headers["ETag"]
- get "/expires/expires_etag", {}, "If-None-Match" => etag
+ get "/expires/expires_etag", {}, { "HTTP_IF_NONE_MATCH" => etag }
assert_equal "stale, valid, store", last_response.headers["X-Rack-Cache"]
- assert_equal body, last_response.body
+ assert_equal 304, last_response.status
+ assert_equal "", last_response.body
end
def test_cache_works_with_etags_private
@@ -138,8 +139,8 @@ module ApplicationTests
body = last_response.body
etag = last_response.headers["ETag"]
- get "/expires/expires_etag", {private: true}, "If-None-Match" => etag
- assert_equal "miss", last_response.headers["X-Rack-Cache"]
+ get "/expires/expires_etag", { private: true }, { "HTTP_IF_NONE_MATCH" => etag }
+ assert_equal "miss", last_response.headers["X-Rack-Cache"]
assert_not_equal body, last_response.body
end
@@ -152,12 +153,12 @@ module ApplicationTests
assert_equal "miss, store", last_response.headers["X-Rack-Cache"]
assert_equal "public", last_response.headers["Cache-Control"]
- body = last_response.body
last = last_response.headers["Last-Modified"]
- get "/expires/expires_last_modified", {}, "If-Modified-Since" => last
+ get "/expires/expires_last_modified", {}, { "HTTP_IF_MODIFIED_SINCE" => last }
assert_equal "stale, valid, store", last_response.headers["X-Rack-Cache"]
- assert_equal body, last_response.body
+ assert_equal 304, last_response.status
+ assert_equal "", last_response.body
end
def test_cache_works_with_last_modified_private
@@ -172,8 +173,8 @@ module ApplicationTests
body = last_response.body
last = last_response.headers["Last-Modified"]
- get "/expires/expires_last_modified", {private: true}, "If-Modified-Since" => last
- assert_equal "miss", last_response.headers["X-Rack-Cache"]
+ get "/expires/expires_last_modified", { private: true }, { "HTTP_IF_MODIFIED_SINCE" => last }
+ assert_equal "miss", last_response.headers["X-Rack-Cache"]
assert_not_equal body, last_response.body
end
end
diff --git a/railties/test/application/middleware/cookies_test.rb b/railties/test/application/middleware/cookies_test.rb
index bbb7627be9..fe48ef3f03 100644
--- a/railties/test/application/middleware/cookies_test.rb
+++ b/railties/test/application/middleware/cookies_test.rb
@@ -1,8 +1,12 @@
-require 'isolation/abstract_unit'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "rack/test"
module ApplicationTests
class CookiesTest < ActiveSupport::TestCase
include ActiveSupport::Testing::Isolation
+ include Rack::Test::Methods
def new_app
File.expand_path("#{app_path}/../new_app")
@@ -10,38 +14,180 @@ module ApplicationTests
def setup
build_app
- boot_rails
FileUtils.rm_rf("#{app_path}/config/environments")
end
+ def app
+ Rails.application
+ end
+
def teardown
teardown_app
FileUtils.rm_rf(new_app) if File.directory?(new_app)
end
- test 'always_write_cookie is true by default in development' do
- require 'rails'
- Rails.env = 'development'
+ test "always_write_cookie is true by default in development" do
+ require "rails"
+ Rails.env = "development"
require "#{app_path}/config/environment"
assert_equal true, ActionDispatch::Cookies::CookieJar.always_write_cookie
end
- test 'always_write_cookie is false by default in production' do
- require 'rails'
- Rails.env = 'production'
+ test "always_write_cookie is false by default in production" do
+ require "rails"
+ Rails.env = "production"
require "#{app_path}/config/environment"
assert_equal false, ActionDispatch::Cookies::CookieJar.always_write_cookie
end
- test 'always_write_cookie can be overridden' do
+ test "always_write_cookie can be overridden" do
add_to_config <<-RUBY
config.action_dispatch.always_write_cookie = false
RUBY
- require 'rails'
- Rails.env = 'development'
+ require "rails"
+ Rails.env = "development"
require "#{app_path}/config/environment"
assert_equal false, ActionDispatch::Cookies::CookieJar.always_write_cookie
end
+
+ test "signed cookies with SHA512 digest and rotated out SHA256 and SHA1 digests" do
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ get ':controller(/:action)'
+ post ':controller(/:action)'
+ end
+ RUBY
+
+ controller :foo, <<-RUBY
+ class FooController < ActionController::Base
+ protect_from_forgery with: :null_session
+
+ def write_raw_cookie_sha1
+ cookies[:signed_cookie] = TestVerifiers.sha1.generate("signed cookie")
+ head :ok
+ end
+
+ def write_raw_cookie_sha256
+ cookies[:signed_cookie] = TestVerifiers.sha256.generate("signed cookie")
+ head :ok
+ end
+
+ def read_signed
+ render plain: cookies.signed[:signed_cookie].inspect
+ end
+
+ def read_raw_cookie
+ render plain: cookies[:signed_cookie]
+ end
+ end
+ RUBY
+
+ add_to_config <<-RUBY
+ sha1_secret = Rails.application.key_generator.generate_key("sha1")
+ sha256_secret = Rails.application.key_generator.generate_key("sha256")
+
+ ::TestVerifiers = Class.new do
+ class_attribute :sha1, default: ActiveSupport::MessageVerifier.new(sha1_secret, digest: "SHA1")
+ class_attribute :sha256, default: ActiveSupport::MessageVerifier.new(sha256_secret, digest: "SHA256")
+ end
+
+ config.action_dispatch.signed_cookie_digest = "SHA512"
+ config.action_dispatch.signed_cookie_salt = "sha512 salt"
+
+ config.action_dispatch.cookies_rotations.tap do |cookies|
+ cookies.rotate :signed, sha1_secret, digest: "SHA1"
+ cookies.rotate :signed, sha256_secret, digest: "SHA256"
+ end
+ RUBY
+
+ require "#{app_path}/config/environment"
+
+ verifier_sha512 = ActiveSupport::MessageVerifier.new(app.key_generator.generate_key("sha512 salt"), digest: :SHA512)
+
+ get "/foo/write_raw_cookie_sha1"
+ get "/foo/read_signed"
+ assert_equal "signed cookie".inspect, last_response.body
+
+ get "/foo/read_raw_cookie"
+ assert_equal "signed cookie", verifier_sha512.verify(last_response.body, purpose: "cookie.signed_cookie")
+
+ get "/foo/write_raw_cookie_sha256"
+ get "/foo/read_signed"
+ assert_equal "signed cookie".inspect, last_response.body
+
+ get "/foo/read_raw_cookie"
+ assert_equal "signed cookie", verifier_sha512.verify(last_response.body, purpose: "cookie.signed_cookie")
+ end
+
+ test "encrypted cookies rotating multiple encryption keys" do
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ get ':controller(/:action)'
+ post ':controller(/:action)'
+ end
+ RUBY
+
+ controller :foo, <<-RUBY
+ class FooController < ActionController::Base
+ protect_from_forgery with: :null_session
+
+ def write_raw_cookie_one
+ cookies[:encrypted_cookie] = TestEncryptors.first_gcm.encrypt_and_sign("encrypted cookie")
+ head :ok
+ end
+
+ def write_raw_cookie_two
+ cookies[:encrypted_cookie] = TestEncryptors.second_gcm.encrypt_and_sign("encrypted cookie")
+ head :ok
+ end
+
+ def read_encrypted
+ render plain: cookies.encrypted[:encrypted_cookie].inspect
+ end
+
+ def read_raw_cookie
+ render plain: cookies[:encrypted_cookie]
+ end
+ end
+ RUBY
+
+ add_to_config <<-RUBY
+ first_secret = Rails.application.key_generator.generate_key("first", 32)
+ second_secret = Rails.application.key_generator.generate_key("second", 32)
+
+ ::TestEncryptors = Class.new do
+ class_attribute :first_gcm, default: ActiveSupport::MessageEncryptor.new(first_secret, cipher: "aes-256-gcm")
+ class_attribute :second_gcm, default: ActiveSupport::MessageEncryptor.new(second_secret, cipher: "aes-256-gcm")
+ end
+
+ config.action_dispatch.use_authenticated_cookie_encryption = true
+ config.action_dispatch.encrypted_cookie_cipher = "aes-256-gcm"
+ config.action_dispatch.authenticated_encrypted_cookie_salt = "salt"
+
+ config.action_dispatch.cookies_rotations.tap do |cookies|
+ cookies.rotate :encrypted, first_secret
+ cookies.rotate :encrypted, second_secret
+ end
+ RUBY
+
+ require "#{app_path}/config/environment"
+
+ encryptor = ActiveSupport::MessageEncryptor.new(app.key_generator.generate_key("salt", 32), cipher: "aes-256-gcm")
+
+ get "/foo/write_raw_cookie_one"
+ get "/foo/read_encrypted"
+ assert_equal "encrypted cookie".inspect, last_response.body
+
+ get "/foo/read_raw_cookie"
+ assert_equal "encrypted cookie", encryptor.decrypt_and_verify(last_response.body, purpose: "cookie.encrypted_cookie")
+
+ get "/foo/write_raw_cookie_two"
+ get "/foo/read_encrypted"
+ assert_equal "encrypted cookie".inspect, last_response.body
+
+ get "/foo/read_raw_cookie"
+ assert_equal "encrypted cookie", encryptor.decrypt_and_verify(last_response.body, purpose: "cookie.encrypted_cookie")
+ end
end
end
diff --git a/railties/test/application/middleware/exceptions_test.rb b/railties/test/application/middleware/exceptions_test.rb
index 639b01b562..17df78ed4e 100644
--- a/railties/test/application/middleware/exceptions_test.rb
+++ b/railties/test/application/middleware/exceptions_test.rb
@@ -1,5 +1,7 @@
-require 'isolation/abstract_unit'
-require 'rack/test'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "rack/test"
module ApplicationTests
class MiddlewareExceptionsTest < ActiveSupport::TestCase
@@ -8,7 +10,6 @@ module ApplicationTests
def setup
build_app
- boot_rails
end
def teardown
@@ -59,7 +60,7 @@ module ApplicationTests
assert_equal "YOU FAILED", last_response.body
end
- test "url generation error when action_dispatch.show_exceptions is set raises an exception" do
+ test "URL generation error when action_dispatch.show_exceptions is set raises an exception" do
controller :foo, <<-RUBY
class FooController < ActionController::Base
def index
@@ -70,7 +71,7 @@ module ApplicationTests
app.config.action_dispatch.show_exceptions = true
- get '/foo'
+ get "/foo"
assert_equal 500, last_response.status
end
@@ -78,7 +79,7 @@ module ApplicationTests
app.config.action_dispatch.show_exceptions = false
assert_raise(ActionController::RoutingError) do
- get '/foo'
+ get "/foo"
end
end
@@ -86,7 +87,7 @@ module ApplicationTests
app.config.action_dispatch.show_exceptions = true
assert_nothing_raised do
- get '/foo'
+ get "/foo"
assert_match "The page you were looking for doesn't exist.", last_response.body
end
end
@@ -96,11 +97,25 @@ module ApplicationTests
app.config.consider_all_requests_local = true
assert_nothing_raised do
- get '/foo'
+ get "/foo"
assert_match "No route matches", last_response.body
end
end
+ test "routing to a nonexistent controller when action_dispatch.show_exceptions and consider_all_requests_local are set shows diagnostics" do
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ resources :articles
+ end
+ RUBY
+
+ app.config.action_dispatch.show_exceptions = true
+ app.config.consider_all_requests_local = true
+
+ get "/articles"
+ assert_match "<title>Action Controller: Exception caught</title>", last_response.body
+ end
+
test "displays diagnostics message when exception raised in template that contains UTF-8" do
controller :foo, <<-RUBY
class FooController < ActionController::Base
@@ -112,12 +127,12 @@ module ApplicationTests
app.config.action_dispatch.show_exceptions = true
app.config.consider_all_requests_local = true
- app_file 'app/views/foo/index.html.erb', <<-ERB
+ app_file "app/views/foo/index.html.erb", <<-ERB
<% raise 'boooom' %>
✓測試テスト시험
ERB
- get '/foo', :utf8 => '✓'
+ get "/foo", utf8: "✓"
assert_match(/boooom/, last_response.body)
assert_match(/測試テスト시험/, last_response.body)
end
diff --git a/railties/test/application/middleware/remote_ip_test.rb b/railties/test/application/middleware/remote_ip_test.rb
index 37bd8a25c1..515b32080e 100644
--- a/railties/test/application/middleware/remote_ip_test.rb
+++ b/railties/test/application/middleware/remote_ip_test.rb
@@ -1,6 +1,8 @@
-require 'ipaddr'
-require 'isolation/abstract_unit'
-require 'active_support/key_generator'
+# frozen_string_literal: true
+
+require "ipaddr"
+require "isolation/abstract_unit"
+require "active_support/key_generator"
module ApplicationTests
class RemoteIpTest < ActiveSupport::TestCase
@@ -9,8 +11,10 @@ module ApplicationTests
def remote_ip(env = {})
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.show_exceptions" => false,
+ "action_dispatch.key_generator" => ActiveSupport::CachingKeyGenerator.new(
+ ActiveSupport::KeyGenerator.new("b3c631c314c0bbca50c1b2843150fe33", iterations: 1000)
+ )
)
endpoint = Proc.new do |e|
@@ -69,7 +73,7 @@ module ApplicationTests
test "the user can set trusted proxies with an IPAddr argument" do
make_basic_app do |app|
- app.config.action_dispatch.trusted_proxies = IPAddr.new('4.2.42.0/24')
+ app.config.action_dispatch.trusted_proxies = IPAddr.new("4.2.42.0/24")
end
assert_equal "1.1.1.1", remote_ip("REMOTE_ADDR" => "1.1.1.1", "HTTP_X_FORWARDED_FOR" => "10.0.0.0,4.2.42.42")
diff --git a/railties/test/application/middleware/sendfile_test.rb b/railties/test/application/middleware/sendfile_test.rb
index be86f1a3b8..818ad61c64 100644
--- a/railties/test/application/middleware/sendfile_test.rb
+++ b/railties/test/application/middleware/sendfile_test.rb
@@ -1,4 +1,6 @@
-require 'isolation/abstract_unit'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
module ApplicationTests
class SendfileTest < ActiveSupport::TestCase
@@ -6,7 +8,6 @@ module ApplicationTests
def setup
build_app
- boot_rails
FileUtils.rm_rf "#{app_path}/config/environments"
end
@@ -14,10 +15,6 @@ module ApplicationTests
teardown_app
end
- def app
- @app ||= Rails.application
- end
-
define_method :simple_controller do
class ::OmgController < ActionController::Base
def index
@@ -32,7 +29,7 @@ module ApplicationTests
simple_controller
get "/"
- assert !last_response.headers["X-Sendfile"]
+ assert_not last_response.headers["X-Sendfile"]
assert_equal File.read(__FILE__), last_response.body
end
@@ -49,7 +46,7 @@ module ApplicationTests
test "config.action_dispatch.x_sendfile_header is sent to Rack::Sendfile" do
make_basic_app do |app|
- app.config.action_dispatch.x_sendfile_header = 'X-Lighttpd-Send-File'
+ app.config.action_dispatch.x_sendfile_header = "X-Lighttpd-Send-File"
end
simple_controller
@@ -60,7 +57,7 @@ module ApplicationTests
test "files handled by ActionDispatch::Static are handled by Rack::Sendfile" do
make_basic_app do |app|
- app.config.action_dispatch.x_sendfile_header = 'X-Sendfile'
+ app.config.action_dispatch.x_sendfile_header = "X-Sendfile"
app.config.public_file_server.enabled = true
app.paths["public"] = File.join(rails_root, "public")
end
diff --git a/railties/test/application/middleware/session_test.rb b/railties/test/application/middleware/session_test.rb
index 85e7761727..479615c133 100644
--- a/railties/test/application/middleware/session_test.rb
+++ b/railties/test/application/middleware/session_test.rb
@@ -1,5 +1,7 @@
-require 'isolation/abstract_unit'
-require 'rack/test'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "rack/test"
module ApplicationTests
class MiddlewareSessionTest < ActiveSupport::TestCase
@@ -8,7 +10,6 @@ module ApplicationTests
def setup
build_app
- boot_rails
FileUtils.rm_rf "#{app_path}/config/environments"
end
@@ -30,7 +31,7 @@ module ApplicationTests
add_to_config "config.force_ssl = true"
add_to_config "config.ssl_options = { secure_cookies: false }"
require "#{app_path}/config/environment"
- assert !app.config.session_options[:secure]
+ assert_not app.config.session_options[:secure]
end
test "session is not loaded if it's not used" do
@@ -50,11 +51,11 @@ module ApplicationTests
get "/"
assert last_request.env["HTTP_COOKIE"]
- assert !last_response.headers["Set-Cookie"]
+ assert_not last_response.headers["Set-Cookie"]
end
test "session is empty and isn't saved on unverified request when using :null_session protect method" do
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get ':controller(/:action)'
post ':controller(/:action)'
@@ -71,7 +72,7 @@ module ApplicationTests
end
def read_session
- render text: session[:foo].inspect
+ render plain: session[:foo].inspect
end
end
RUBY
@@ -82,20 +83,20 @@ module ApplicationTests
require "#{app_path}/config/environment"
- get '/foo/write_session'
- get '/foo/read_session'
- assert_equal '1', last_response.body
+ get "/foo/write_session"
+ get "/foo/read_session"
+ assert_equal "1", last_response.body
- post '/foo/read_session' # Read session using POST request without CSRF token
- assert_equal 'nil', last_response.body # Stored value shouldn't be accessible
+ post "/foo/read_session" # Read session using POST request without CSRF token
+ assert_equal "nil", last_response.body # Stored value shouldn't be accessible
- post '/foo/write_session' # Write session using POST request without CSRF token
- get '/foo/read_session' # Session shouldn't be changed
- assert_equal '1', last_response.body
+ post "/foo/write_session" # Write session using POST request without CSRF token
+ get "/foo/read_session" # Session shouldn't be changed
+ assert_equal "1", last_response.body
end
test "cookie jar is empty and isn't saved on unverified request when using :null_session protect method" do
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get ':controller(/:action)'
post ':controller(/:action)'
@@ -112,7 +113,7 @@ module ApplicationTests
end
def read_cookie
- render text: cookies[:foo].inspect
+ render plain: cookies[:foo].inspect
end
end
RUBY
@@ -123,20 +124,20 @@ module ApplicationTests
require "#{app_path}/config/environment"
- get '/foo/write_cookie'
- get '/foo/read_cookie'
+ get "/foo/write_cookie"
+ get "/foo/read_cookie"
assert_equal '"1"', last_response.body
- post '/foo/read_cookie' # Read cookie using POST request without CSRF token
- assert_equal 'nil', last_response.body # Stored value shouldn't be accessible
+ post "/foo/read_cookie" # Read cookie using POST request without CSRF token
+ assert_equal "nil", last_response.body # Stored value shouldn't be accessible
- post '/foo/write_cookie' # Write cookie using POST request without CSRF token
- get '/foo/read_cookie' # Cookie shouldn't be changed
+ post "/foo/write_cookie" # Write cookie using POST request without CSRF token
+ get "/foo/read_cookie" # Cookie shouldn't be changed
assert_equal '"1"', last_response.body
end
test "session using encrypted cookie store" do
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get ':controller(/:action)'
end
@@ -150,38 +151,43 @@ module ApplicationTests
end
def read_session
- render text: session[:foo]
+ render plain: session[:foo]
end
def read_encrypted_cookie
- render text: cookies.encrypted[:_myapp_session]['foo']
+ render plain: cookies.encrypted[:_myapp_session]['foo']
end
def read_raw_cookie
- render text: cookies[:_myapp_session]
+ render plain: cookies[:_myapp_session]
end
end
RUBY
+ add_to_config <<-RUBY
+ # Enable AEAD cookies
+ config.action_dispatch.use_authenticated_cookie_encryption = true
+ RUBY
+
require "#{app_path}/config/environment"
- get '/foo/write_session'
- get '/foo/read_session'
- assert_equal '1', last_response.body
+ get "/foo/write_session"
+ get "/foo/read_session"
+ assert_equal "1", last_response.body
- get '/foo/read_encrypted_cookie'
- assert_equal '1', last_response.body
+ get "/foo/read_encrypted_cookie"
+ assert_equal "1", last_response.body
- secret = app.key_generator.generate_key('encrypted cookie')
- sign_secret = app.key_generator.generate_key('signed encrypted cookie')
- encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret)
+ 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 1, encryptor.decrypt_and_verify(last_response.body)['foo']
+ get "/foo/read_raw_cookie"
+ assert_equal 1, encryptor.decrypt_and_verify(last_response.body, purpose: "cookie._myapp_session")["foo"]
end
test "session upgrading signature to encryption cookie store works the same way as encrypted cookie store" do
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get ':controller(/:action)'
end
@@ -195,42 +201,43 @@ module ApplicationTests
end
def read_session
- render text: session[:foo]
+ render plain: session[:foo]
end
def read_encrypted_cookie
- render text: cookies.encrypted[:_myapp_session]['foo']
+ render plain: cookies.encrypted[:_myapp_session]['foo']
end
def read_raw_cookie
- render text: cookies[:_myapp_session]
+ 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_session'
- get '/foo/read_session'
- assert_equal '1', last_response.body
+ get "/foo/write_session"
+ get "/foo/read_session"
+ assert_equal "1", last_response.body
- get '/foo/read_encrypted_cookie'
- assert_equal '1', last_response.body
+ get "/foo/read_encrypted_cookie"
+ assert_equal "1", last_response.body
- secret = app.key_generator.generate_key('encrypted cookie')
- sign_secret = app.key_generator.generate_key('signed encrypted cookie')
- encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret)
+ 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 1, encryptor.decrypt_and_verify(last_response.body)['foo']
+ get "/foo/read_raw_cookie"
+ 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
+ test "session upgrading from AES-CBC-HMAC encryption to AES-GCM encryption" do
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get ':controller(/:action)'
end
@@ -239,8 +246,9 @@ module ApplicationTests
controller :foo, <<-RUBY
class FooController < ActionController::Base
def write_raw_session
+ # AES-256-CBC with SHA1 HMAC
# {"session_id"=>"1965d95720fffc123941bdfb7d2e6870", "foo"=>1}
- cookies[:_myapp_session] = "BAh7B0kiD3Nlc3Npb25faWQGOgZFRkkiJTE5NjVkOTU3MjBmZmZjMTIzOTQxYmRmYjdkMmU2ODcwBjsAVEkiCGZvbwY7AEZpBg==--315fb9931921a87ae7421aec96382f0294119749"
+ cookies[:_myapp_session] = "TlgrdS85aUpDd1R2cDlPWlR6K0FJeGExckwySjZ2Z0pkR3d2QnRObGxZT25aalJWYWVvbFVLcHF4d0VQVDdSaFF2QjFPbG9MVjJzeWp3YjcyRUlKUUU2ZlR4bXlSNG9ZUkJPRUtld0E3dVU9LS0xNDZXbGpRZ3NjdW43N2haUEZJSUNRPT0=--3639b5ce54c09495cfeaae928cd5634e0c4b2e96"
head :ok
end
@@ -250,104 +258,56 @@ module ApplicationTests
end
def read_session
- render text: session[:foo]
+ render plain: session[:foo]
end
def read_encrypted_cookie
- render text: cookies.encrypted[:_myapp_session]['foo']
+ render plain: cookies.encrypted[:_myapp_session]['foo']
end
def read_raw_cookie
- render text: cookies[:_myapp_session]
+ render plain: cookies[:_myapp_session]
end
end
RUBY
add_to_config <<-RUBY
- secrets.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
- 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
+ # Use a static key
+ Rails.application.credentials.secret_key_base = "known key base"
- get '/foo/read_encrypted_cookie'
- assert_equal '2', last_response.body
-
- secret = app.key_generator.generate_key('encrypted cookie')
- sign_secret = app.key_generator.generate_key('signed encrypted cookie')
- encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret)
-
- get '/foo/read_raw_cookie'
- assert_equal 2, encryptor.decrypt_and_verify(last_response.body)['foo']
- 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
+ # Enable AEAD cookies
+ config.action_dispatch.use_authenticated_cookie_encryption = true
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
+ begin
+ old_rails_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "production"
- def write_session
- session[:foo] = session[:foo] + 1
- head :ok
- end
-
- def read_session
- render text: session[:foo]
- end
-
- def read_signed_cookie
- render text: cookies.signed[:_myapp_session]['foo']
- end
-
- def read_raw_cookie
- render text: cookies[:_myapp_session]
- end
- end
- RUBY
-
- add_to_config <<-RUBY
- secrets.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
- secrets.secret_key_base = nil
- RUBY
+ require "#{app_path}/config/environment"
- require "#{app_path}/config/environment"
+ get "/foo/write_raw_session"
+ get "/foo/read_session"
+ assert_equal "1", last_response.body
- 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/write_session'
- get '/foo/read_session'
- assert_equal '2', last_response.body
+ get "/foo/read_encrypted_cookie"
+ assert_equal "2", last_response.body
- get '/foo/read_signed_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)
- verifier = ActiveSupport::MessageVerifier.new(app.secrets.secret_token)
-
- get '/foo/read_raw_cookie'
- assert_equal 2, verifier.verify(last_response.body)['foo']
+ get "/foo/read_raw_cookie"
+ assert_equal 2, encryptor.decrypt_and_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'
+ test "calling reset_session on request does not trigger an error for API apps" do
+ add_to_config "config.api_only = true"
controller :test, <<-RUBY
class TestController < ApplicationController
@@ -358,7 +318,7 @@ module ApplicationTests
end
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get '/dump_flash' => "test#dump_flash"
end
@@ -366,12 +326,18 @@ module ApplicationTests
require "#{app_path}/config/environment"
- get '/dump_flash'
+ get "/dump_flash"
assert_equal 200, last_response.status
- assert_equal 'It worked!', last_response.body
+ assert_equal "It worked!", last_response.body
- refute Rails.application.middleware.include?(ActionDispatch::Flash)
+ assert_not_includes Rails.application.middleware, ActionDispatch::Flash
+ end
+
+ test "cookie_only is set to true even if user tries to overwrite it" do
+ add_to_config "config.session_store :cookie_store, key: '_myapp_session', cookie_only: false"
+ require "#{app_path}/config/environment"
+ assert app.config.session_options[:cookie_only], "Expected cookie_only to be set to true"
end
end
end
diff --git a/railties/test/application/middleware/static_test.rb b/railties/test/application/middleware/static_test.rb
index 1246e20d94..0977042cfe 100644
--- a/railties/test/application/middleware/static_test.rb
+++ b/railties/test/application/middleware/static_test.rb
@@ -1,5 +1,7 @@
-require 'isolation/abstract_unit'
-require 'rack/test'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "rack/test"
module ApplicationTests
class MiddlewareStaticTest < ActiveSupport::TestCase
@@ -18,17 +20,17 @@ module ApplicationTests
# Regression test to #8907
# See https://github.com/rails/rails/commit/9cc82b77196d21a5c7021f6dca59ab9b2b158a45#commitcomment-2416514
test "doesn't set Cache-Control header when it is nil" do
- app_file "public/foo.html", 'static'
+ app_file "public/foo.html", "static"
require "#{app_path}/config/environment"
- get 'foo'
+ get "foo"
- assert_not last_response.headers.has_key?('Cache-Control'), "Cache-Control should not be set"
+ assert_not last_response.headers.has_key?("Cache-Control"), "Cache-Control should not be set"
end
test "headers for static files are configurable" do
- app_file "public/about.html", 'static'
+ app_file "public/about.html", "static"
add_to_config <<-CONFIG
config.public_file_server.headers = {
"Access-Control-Allow-Origin" => "http://rubyonrails.org",
@@ -38,19 +40,19 @@ module ApplicationTests
require "#{app_path}/config/environment"
- get '/about.html'
+ get "/about.html"
- assert_equal 'http://rubyonrails.org', last_response.headers["Access-Control-Allow-Origin"]
- assert_equal 'public, max-age=60', last_response.headers["Cache-Control"]
+ assert_equal "http://rubyonrails.org", last_response.headers["Access-Control-Allow-Origin"]
+ assert_equal "public, max-age=60", last_response.headers["Cache-Control"]
end
test "public_file_server.index_name defaults to 'index'" do
app_file "public/index.html", "/index.html"
-
+
require "#{app_path}/config/environment"
- get '/'
-
+ get "/"
+
assert_equal "/index.html\n", last_response.body
end
@@ -60,7 +62,7 @@ module ApplicationTests
require "#{app_path}/config/environment"
- get '/'
+ get "/"
assert_equal "/other-index.html\n", last_response.body
end
diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb
index 5869ff64bc..4242daf39a 100644
--- a/railties/test/application/middleware_test.rb
+++ b/railties/test/application/middleware_test.rb
@@ -1,4 +1,6 @@
-require 'isolation/abstract_unit'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
module ApplicationTests
class MiddlewareTest < ActiveSupport::TestCase
@@ -6,7 +8,6 @@ module ApplicationTests
def setup
build_app
- boot_rails
FileUtils.rm_rf "#{app_path}/config/environments"
end
@@ -24,6 +25,8 @@ module ApplicationTests
boot!
assert_equal [
+ "Webpacker::DevServerProxy",
+ "ActionDispatch::HostAuthorization",
"Rack::Sendfile",
"ActionDispatch::Static",
"ActionDispatch::Executor",
@@ -31,19 +34,21 @@ module ApplicationTests
"Rack::Runtime",
"Rack::MethodOverride",
"ActionDispatch::RequestId",
- "Rails::Rack::Logger", # must come after Rack::MethodOverride to properly log overridden methods
+ "ActionDispatch::RemoteIp",
+ "Rails::Rack::Logger",
"ActionDispatch::ShowExceptions",
"ActionDispatch::DebugExceptions",
- "ActionDispatch::RemoteIp",
"ActionDispatch::Reloader",
"ActionDispatch::Callbacks",
"ActiveRecord::Migration::CheckPending",
"ActionDispatch::Cookies",
"ActionDispatch::Session::CookieStore",
"ActionDispatch::Flash",
+ "ActionDispatch::ContentSecurityPolicy::Middleware",
"Rack::Head",
"Rack::ConditionalGet",
- "Rack::ETag"
+ "Rack::ETag",
+ "Rack::TempfileReaper"
], middleware
end
@@ -53,16 +58,18 @@ module ApplicationTests
boot!
assert_equal [
+ "Webpacker::DevServerProxy",
+ "ActionDispatch::HostAuthorization",
"Rack::Sendfile",
"ActionDispatch::Static",
"ActionDispatch::Executor",
"ActiveSupport::Cache::Strategy::LocalCache",
"Rack::Runtime",
"ActionDispatch::RequestId",
- "Rails::Rack::Logger", # must come after Rack::MethodOverride to properly log overridden methods
+ "ActionDispatch::RemoteIp",
+ "Rails::Rack::Logger",
"ActionDispatch::ShowExceptions",
"ActionDispatch::DebugExceptions",
- "ActionDispatch::RemoteIp",
"ActionDispatch::Reloader",
"ActionDispatch::Callbacks",
"Rack::Head",
@@ -71,10 +78,41 @@ module ApplicationTests
], middleware
end
+ test "middleware dependencies" do
+ boot!
+
+ # The following array-of-arrays describes dependencies between
+ # middlewares: the first item in each list depends on the
+ # remaining items (and therefore must occur later in the
+ # middleware stack).
+
+ dependencies = [
+ # Logger needs a fully "corrected" request environment
+ %w(Rails::Rack::Logger Rack::MethodOverride ActionDispatch::RequestId ActionDispatch::RemoteIp),
+
+ # Serving public/ doesn't invoke user code, so it should skip
+ # locks etc
+ %w(ActionDispatch::Executor ActionDispatch::Static),
+
+ # Errors during reload must be reported
+ %w(ActionDispatch::Reloader ActionDispatch::ShowExceptions ActionDispatch::DebugExceptions),
+
+ # Outright dependencies
+ %w(ActionDispatch::Static Rack::Sendfile),
+ %w(ActionDispatch::Flash ActionDispatch::Session::CookieStore),
+ %w(ActionDispatch::Session::CookieStore ActionDispatch::Cookies),
+ ]
+
+ require "tsort"
+ sorted = TSort.tsort((middleware | dependencies.flatten).method(:each),
+ lambda { |n, &b| dependencies.each { |m, *ds| ds.each(&b) if m == n } })
+ assert_equal sorted, middleware
+ end
+
test "Rack::Cache is not included by default" do
boot!
- assert !middleware.include?("Rack::Cache"), "Rack::Cache is not included in the default stack unless you set config.action_dispatch.rack_cache"
+ assert_not_includes middleware, "Rack::Cache", "Rack::Cache is not included in the default stack unless you set config.action_dispatch.rack_cache"
end
test "Rack::Cache is present when action_dispatch.rack_cache is set" do
@@ -82,7 +120,7 @@ module ApplicationTests
boot!
- assert middleware.include?("Rack::Cache")
+ assert_includes middleware, "Rack::Cache"
end
test "ActiveRecord::Migration::CheckPending is present when active_record.migration_error is set to :page_load" do
@@ -90,27 +128,27 @@ module ApplicationTests
boot!
- assert middleware.include?("ActiveRecord::Migration::CheckPending")
+ assert_includes middleware, "ActiveRecord::Migration::CheckPending"
end
test "ActionDispatch::SSL is present when force_ssl is set" do
add_to_config "config.force_ssl = true"
boot!
- assert middleware.include?("ActionDispatch::SSL")
+ assert_includes middleware, "ActionDispatch::SSL"
end
test "ActionDispatch::SSL is configured with options when given" do
add_to_config "config.force_ssl = true"
- add_to_config "config.ssl_options = { host: 'example.com' }"
+ add_to_config "config.ssl_options = { redirect: { host: 'example.com' } }"
boot!
- assert_equal [{host: 'example.com'}], Rails.application.middleware.first.args
+ assert_equal [{ redirect: { host: "example.com" } }], Rails.application.middleware[2].args
end
test "removing Active Record omits its middleware" do
use_frameworks []
boot!
- assert !middleware.include?("ActiveRecord::Migration::CheckPending")
+ assert_not_includes middleware, "ActiveRecord::Migration::CheckPending"
end
test "includes executor" do
@@ -140,20 +178,20 @@ module ApplicationTests
test "removes static asset server if public_file_server.enabled is disabled" do
add_to_config "config.public_file_server.enabled = false"
boot!
- assert !middleware.include?("ActionDispatch::Static")
+ assert_not_includes middleware, "ActionDispatch::Static"
end
test "can delete a middleware from the stack" do
add_to_config "config.middleware.delete ActionDispatch::Static"
boot!
- assert !middleware.include?("ActionDispatch::Static")
+ assert_not_includes middleware, "ActionDispatch::Static"
end
test "can delete a middleware from the stack even if insert_before is added after delete" do
add_to_config "config.middleware.delete Rack::Runtime"
add_to_config "config.middleware.insert_before(Rack::Runtime, Rack::Config)"
boot!
- assert middleware.include?("Rack::Config")
+ assert_includes middleware, "Rack::Config"
assert_not middleware.include?("Rack::Runtime")
end
@@ -161,21 +199,21 @@ module ApplicationTests
add_to_config "config.middleware.delete Rack::Runtime"
add_to_config "config.middleware.insert_after(Rack::Runtime, Rack::Config)"
boot!
- assert middleware.include?("Rack::Config")
+ assert_includes middleware, "Rack::Config"
assert_not middleware.include?("Rack::Runtime")
end
test "includes exceptions middlewares even if action_dispatch.show_exceptions is disabled" do
add_to_config "config.action_dispatch.show_exceptions = false"
boot!
- assert middleware.include?("ActionDispatch::ShowExceptions")
- assert middleware.include?("ActionDispatch::DebugExceptions")
+ assert_includes middleware, "ActionDispatch::ShowExceptions"
+ assert_includes middleware, "ActionDispatch::DebugExceptions"
end
test "removes ActionDispatch::Reloader if cache_classes is true" do
add_to_config "config.cache_classes = true"
boot!
- assert !middleware.include?("ActionDispatch::Reloader")
+ assert_not_includes middleware, "ActionDispatch::Reloader"
end
test "use middleware" do
@@ -188,35 +226,36 @@ module ApplicationTests
test "insert middleware after" do
add_to_config "config.middleware.insert_after Rack::Sendfile, Rack::Config"
boot!
- assert_equal "Rack::Config", middleware.second
+ assert_equal "Rack::Config", middleware.fourth
end
- test 'unshift middleware' do
- add_to_config 'config.middleware.unshift Rack::Config'
+ test "unshift middleware" do
+ add_to_config "config.middleware.unshift Rack::Config"
boot!
- assert_equal 'Rack::Config', middleware.first
+ assert_equal "Rack::Config", middleware.second
end
test "Rails.cache does not respond to middleware" do
add_to_config "config.cache_store = :memory_store"
boot!
- assert_equal "Rack::Runtime", middleware.fourth
+ assert_equal "Rack::Runtime", middleware[5]
end
test "Rails.cache does respond to middleware" do
boot!
- assert_equal "Rack::Runtime", middleware.fifth
+ 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.first
+ assert_equal "Rack::Config", middleware.third
end
test "can't change middleware after it's built" do
boot!
- assert_raise RuntimeError do
+ assert_raise FrozenError do
app.config.middleware.use Rack::Config
end
end
@@ -228,35 +267,35 @@ module ApplicationTests
class ::OmgController < ActionController::Base
def index
if params[:nothing]
- render text: ""
+ render plain: ""
else
- render text: "OMG"
+ render plain: "OMG"
end
end
end
- etag = "W/" + "5af83e3196bf99f440f31f2e1a6c9afe".inspect
+ etag = "W/" + "c00862d1c6c1cf7c1b49388306e7b3c1".inspect
get "/"
assert_equal 200, last_response.status
assert_equal "OMG", last_response.body
- assert_equal "text/html; charset=utf-8", last_response.headers["Content-Type"]
+ assert_equal "text/plain; charset=utf-8", last_response.headers["Content-Type"]
assert_equal "max-age=0, private, must-revalidate", last_response.headers["Cache-Control"]
assert_equal etag, last_response.headers["Etag"]
- get "/", {}, "HTTP_IF_NONE_MATCH" => etag
+ get "/", {}, { "HTTP_IF_NONE_MATCH" => etag }
assert_equal 304, last_response.status
assert_equal "", last_response.body
- assert_equal nil, last_response.headers["Content-Type"]
+ assert_nil last_response.headers["Content-Type"]
assert_equal "max-age=0, private, must-revalidate", last_response.headers["Cache-Control"]
assert_equal etag, last_response.headers["Etag"]
get "/?nothing=true"
assert_equal 200, last_response.status
assert_equal "", last_response.body
- assert_equal "text/html; charset=utf-8", last_response.headers["Content-Type"]
+ assert_equal "text/plain; charset=utf-8", last_response.headers["Content-Type"]
assert_equal "no-cache", last_response.headers["Cache-Control"]
- assert_equal nil, last_response.headers["Etag"]
+ assert_nil last_response.headers["Etag"]
end
test "ORIGINAL_FULLPATH is passed to env" do
diff --git a/railties/test/application/multiple_applications_test.rb b/railties/test/application/multiple_applications_test.rb
index f2770a9cb4..f0f1112f6b 100644
--- a/railties/test/application/multiple_applications_test.rb
+++ b/railties/test/application/multiple_applications_test.rb
@@ -1,4 +1,6 @@
-require 'isolation/abstract_unit'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
module ApplicationTests
class MultipleApplicationsTest < ActiveSupport::TestCase
@@ -6,9 +8,8 @@ module ApplicationTests
def setup
build_app(initializers: true)
- boot_rails
require "#{rails_root}/config/environment"
- Rails.application.config.some_setting = 'something_or_other'
+ Rails.application.config.some_setting = "something_or_other"
end
def teardown
@@ -88,9 +89,9 @@ module ApplicationTests
require "#{app_path}/config/environment"
assert_equal 0, run_count, "The count should stay at zero without any calls to the rake tasks"
- require 'rake'
- require 'rake/testtask'
- require 'rdoc/task'
+ require "rake"
+ require "rake/testtask"
+ require "rdoc/task"
Rails.application.load_tasks
assert_equal 2, run_count, "Calling a rake task should result in two increments to the count"
end
@@ -99,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 }
@@ -164,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/paths_test.rb b/railties/test/application/paths_test.rb
index 4029984ce9..28a9206daa 100644
--- a/railties/test/application/paths_test.rb
+++ b/railties/test/application/paths_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "isolation/abstract_unit"
module ApplicationTests
@@ -6,7 +8,6 @@ module ApplicationTests
def setup
build_app
- boot_rails
FileUtils.rm_rf("#{app_path}/config/environments")
app_file "config/environments/development.rb", ""
add_to_config <<-RUBY
@@ -36,7 +37,7 @@ module ApplicationTests
end
def assert_not_in_load_path(*path)
- assert !$:.any? { |p| File.expand_path(p) == root(*path) }, "Load path includes '#{root(*path)}'. They are:\n-----\n #{$:.join("\n")}\n-----"
+ assert_not $:.any? { |p| File.expand_path(p) == root(*path) }, "Load path includes '#{root(*path)}'. They are:\n-----\n #{$:.join("\n")}\n-----"
end
test "booting up Rails yields a valid paths object" do
@@ -56,9 +57,9 @@ module ApplicationTests
test "booting up Rails yields a list of paths that are eager" do
eager_load = @paths.eager_load
- assert eager_load.include?(root("app/controllers"))
- assert eager_load.include?(root("app/helpers"))
- assert eager_load.include?(root("app/models"))
+ assert_includes eager_load, root("app/controllers")
+ assert_includes eager_load, root("app/helpers")
+ assert_includes eager_load, root("app/models")
end
test "environments has a glob equal to the current environment" do
diff --git a/railties/test/application/per_request_digest_cache_test.rb b/railties/test/application/per_request_digest_cache_test.rb
index dfe3fc9354..ab055c7648 100644
--- a/railties/test/application/per_request_digest_cache_test.rb
+++ b/railties/test/application/per_request_digest_cache_test.rb
@@ -1,33 +1,37 @@
-require 'isolation/abstract_unit'
-require 'rack/test'
-require 'minitest/mock'
+# frozen_string_literal: true
-require 'action_view'
-require 'active_support/testing/method_call_assertions'
+require "isolation/abstract_unit"
+require "rack/test"
+require "minitest/mock"
+
+require "action_view"
class PerRequestDigestCacheTest < ActiveSupport::TestCase
include ActiveSupport::Testing::Isolation
- include ActiveSupport::Testing::MethodCallAssertions
include Rack::Test::Methods
setup do
build_app
- add_to_config 'config.consider_all_requests_local = true'
+ add_to_config "config.consider_all_requests_local = true"
- app_file 'app/models/customer.rb', <<-RUBY
+ app_file "app/models/customer.rb", <<-RUBY
class Customer < Struct.new(:name, :id)
extend ActiveModel::Naming
include ActiveModel::Conversion
+
+ def cache_key
+ [ name, id ].join("/")
+ end
end
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
resources :customers, only: :index
end
RUBY
- app_file 'app/controllers/customers_controller.rb', <<-RUBY
+ app_file "app/controllers/customers_controller.rb", <<-RUBY
class CustomersController < ApplicationController
self.perform_caching = true
@@ -37,7 +41,7 @@ class PerRequestDigestCacheTest < ActiveSupport::TestCase
end
RUBY
- app_file 'app/views/customers/_customer.html.erb', <<-RUBY
+ app_file "app/views/customers/_customer.html.erb", <<-RUBY
<% cache customer do %>
<%= customer.name %>
<% end %>
@@ -49,17 +53,17 @@ class PerRequestDigestCacheTest < ActiveSupport::TestCase
teardown :teardown_app
test "digests are reused when rendering the same template twice" do
- get '/customers'
+ get "/customers"
assert_equal 200, last_response.status
values = ActionView::LookupContext::DetailsKey.digest_caches.first.values
- assert_equal [ '8ba099b7749542fe765ff34a6824d548' ], values
+ assert_equal [ "effc8928d0b33535c8a21d24ec617161" ], values
assert_equal %w(david dingus), last_response.body.split.map(&:strip)
end
test "template digests are cleared before a request" do
assert_called(ActionView::LookupContext::DetailsKey, :clear) do
- get '/customers'
+ get "/customers"
assert_equal 200, last_response.status
end
end
diff --git a/railties/test/application/rack/logger_test.rb b/railties/test/application/rack/logger_test.rb
index 0082ec9cd2..ea425d5fa5 100644
--- a/railties/test/application/rack/logger_test.rb
+++ b/railties/test/application/rack/logger_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "isolation/abstract_unit"
require "active_support/log_subscriber/test_helper"
require "rack/test"
@@ -41,16 +43,22 @@ module ApplicationTests
end
test "logger logs HTTP verb override" do
- post "/", _method: 'put'
+ post "/", _method: "put"
wait
assert_match 'Started PUT "/"', logs
end
test "logger logs HEAD requests" do
- post "/", _method: 'head'
+ post "/", _method: "head"
wait
assert_match 'Started HEAD "/"', logs
end
+
+ test "logger logs correct remote IP address" do
+ get "/", {}, { "REMOTE_ADDR" => "127.0.0.1", "HTTP_X_FORWARDED_FOR" => "1.2.3.4" }
+ wait
+ assert_match 'Started GET "/" for 1.2.3.4', logs
+ end
end
end
end
diff --git a/railties/test/application/rackup_test.rb b/railties/test/application/rackup_test.rb
index 49ac9fc66c..383f18a7da 100644
--- a/railties/test/application/rackup_test.rb
+++ b/railties/test/application/rackup_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "isolation/abstract_unit"
module ApplicationTests
@@ -12,14 +14,13 @@ module ApplicationTests
def setup
build_app
- boot_rails
end
def teardown
teardown_app
end
- test "rails app is present" do
+ test "Rails app is present" do
assert File.exist?(app_path("config"))
end
@@ -37,7 +38,7 @@ module ApplicationTests
test "the config object is available on the application object" do
rackup
- assert_equal 'UTC', Rails.application.config.time_zone
+ assert_equal "UTC", Rails.application.config.time_zone
end
end
end
diff --git a/railties/test/application/rake/dbs_test.rb b/railties/test/application/rake/dbs_test.rb
index a229609e84..258066a7e6 100644
--- a/railties/test/application/rake/dbs_test.rb
+++ b/railties/test/application/rake/dbs_test.rb
@@ -1,14 +1,15 @@
+# frozen_string_literal: true
+
require "isolation/abstract_unit"
-require "active_support/core_ext/string/strip"
+require "env_helpers"
module ApplicationTests
module RakeTests
class RakeDbsTest < ActiveSupport::TestCase
- include ActiveSupport::Testing::Isolation
+ include ActiveSupport::Testing::Isolation, EnvHelpers
def setup
build_app
- boot_rails
FileUtils.rm_rf("#{app_path}/config/environments")
end
@@ -21,53 +22,126 @@ module ApplicationTests
end
def set_database_url
- ENV['DATABASE_URL'] = "sqlite3:#{database_url_db_name}"
+ ENV["DATABASE_URL"] = "sqlite3:#{database_url_db_name}"
# ensure it's using the DATABASE_URL
FileUtils.rm_rf("#{app_path}/config/database.yml")
end
- def db_create_and_drop(expected_database)
+ def db_create_and_drop(expected_database, environment_loaded: true)
Dir.chdir(app_path) do
- output = `bin/rails db:create`
- assert_empty output
+ output = rails("db:create")
+ assert_match(/Created database/, output)
assert File.exist?(expected_database)
- assert_equal expected_database, ActiveRecord::Base.connection_config[:database]
- output = `bin/rails db:drop`
- assert_empty output
- assert !File.exist?(expected_database)
+ yield if block_given?
+ assert_equal expected_database, ActiveRecord::Base.connection_config[:database] if environment_loaded
+ output = rails("db:drop")
+ assert_match(/Dropped database/, output)
+ assert_not File.exist?(expected_database)
end
end
- test 'db:create and db:drop without database url' do
+ 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']
+ db_create_and_drop ActiveRecord::Base.configurations[Rails.env]["database"]
end
- test 'db:create and db:drop with database url' do
+ test "db:create and db:drop with database URL" do
require "#{app_path}/config/environment"
set_database_url
db_create_and_drop database_url_db_name
end
+ test "db:create and db:drop respect environment setting" do
+ app_file "config/database.yml", <<-YAML
+ <% 1 %>
+ development:
+ database: <%= Rails.application.config.database %>
+ 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 with multiline ERB" do
+ app_file "config/database.yml", <<-YAML
+ development:
+ database: <%=
+ Rails.application.config.database
+ %>
+ 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 containing conditional statements in ERB" do
+ app_file "config/database.yml", <<-YAML
+ development:
+ <% if Rails.application.config.database %>
+ database: <%= Rails.application.config.database %>
+ <% else %>
+ database: db/default.sqlite3
+ <% end %>
+ 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 containing multiple ERB statements on the same line" do
+ app_file "config/database.yml", <<-YAML
+ development:
+ database: <% if Rails.application.config.database %><%= Rails.application.config.database %><% else %>db/default.sqlite3<% end %>
+ 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
- `bin/rails db:create`
+ rails "db:create"
yield
- `bin/rails db:drop`
+ rails "db:drop"
end
end
- test 'db:create failure because database exists' do
+ test "db:create failure because database exists" do
with_database_existing do
- output = `bin/rails db:create 2>&1`
+ output = rails("db:create")
assert_match(/already exists/, output)
- assert_equal 0, $?.exitstatus
end
end
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
@@ -75,48 +149,110 @@ module ApplicationTests
end
end
- test 'db:create failure because bad permissions' do
+ test "db:create failure because bad permissions" do
with_bad_permissions do
- output = `bin/rails db:create 2>&1`
- assert_match(/Couldn't create database/, output)
+ output = rails("db:create", allow_failure: true)
+ assert_match("Couldn't create '#{database_url_db_name}' database. Please check your configuration.", output)
assert_equal 1, $?.exitstatus
end
end
- test 'db:drop failure because database does not exist' do
- Dir.chdir(app_path) do
- output = `bin/rails db:drop:_unsafe --trace 2>&1`
- assert_match(/does not exist/, output)
+ test "db:create works when schema cache exists and database does not exist" do
+ use_postgresql
+
+ begin
+ rails %w(db:create db:migrate db:schema:cache:dump)
+
+ rails "db:drop"
+ rails "db:create"
assert_equal 0, $?.exitstatus
+ ensure
+ rails "db:drop" rescue nil
end
end
- test 'db:drop failure because bad permissions' do
+ test "db:drop failure because database does not exist" do
+ output = rails("db:drop:_unsafe", "--trace")
+ assert_match(/does not exist/, output)
+ end
+
+ test "db:drop failure because bad permissions" do
with_database_existing do
with_bad_permissions do
- output = `bin/rails db:drop 2>&1`
+ output = rails("db:drop", allow_failure: true)
assert_match(/Couldn't drop/, output)
assert_equal 1, $?.exitstatus
end
end
end
- def db_migrate_and_status(expected_database)
+ test "db:truncate_all truncates all non-internal tables" do
Dir.chdir(app_path) do
- `bin/rails generate model book title:string;
- bin/rails db:migrate`
- output = `bin/rails db:migrate:status`
- assert_match(%r{database:\s+\S*#{Regexp.escape(expected_database)}}, output)
- assert_match(/up\s+\d{14}\s+Create books/, output)
+ rails "generate", "model", "book", "title:string"
+ rails "db:migrate"
+ require "#{app_path}/config/environment"
+ Book.create!(title: "Remote")
+ assert_equal 1, Book.count
+ schema_migrations = ActiveRecord::Base.connection.execute("SELECT * from \"#{ActiveRecord::Base.schema_migrations_table_name}\"")
+ internal_metadata = ActiveRecord::Base.connection.execute("SELECT * from \"#{ActiveRecord::Base.internal_metadata_table_name}\"")
+
+ rails "db:truncate_all"
+
+ assert_equal(
+ schema_migrations,
+ ActiveRecord::Base.connection.execute("SELECT * from \"#{ActiveRecord::Base.schema_migrations_table_name}\"")
+ )
+ assert_equal(
+ internal_metadata,
+ ActiveRecord::Base.connection.execute("SELECT * from \"#{ActiveRecord::Base.internal_metadata_table_name}\"")
+ )
+ assert_equal 0, Book.count
end
end
- test 'db:migrate and db:migrate:status without database_url' do
+ test "db:truncate_all does not truncate any tables when environment is protected" do
+ with_rails_env "production" do
+ Dir.chdir(app_path) do
+ rails "generate", "model", "book", "title:string"
+ rails "db:migrate"
+ require "#{app_path}/config/environment"
+ Book.create!(title: "Remote")
+ assert_equal 1, Book.count
+ schema_migrations = ActiveRecord::Base.connection.execute("SELECT * from \"#{ActiveRecord::Base.schema_migrations_table_name}\"")
+ internal_metadata = ActiveRecord::Base.connection.execute("SELECT * from \"#{ActiveRecord::Base.internal_metadata_table_name}\"")
+ books = ActiveRecord::Base.connection.execute("SELECT * from \"books\"")
+
+ output = rails("db:truncate_all", allow_failure: true)
+ assert_match(/ActiveRecord::ProtectedEnvironmentError/, output)
+
+ assert_equal(
+ schema_migrations,
+ ActiveRecord::Base.connection.execute("SELECT * from \"#{ActiveRecord::Base.schema_migrations_table_name}\"")
+ )
+ assert_equal(
+ internal_metadata,
+ ActiveRecord::Base.connection.execute("SELECT * from \"#{ActiveRecord::Base.internal_metadata_table_name}\"")
+ )
+ assert_equal 1, Book.count
+ assert_equal(books, ActiveRecord::Base.connection.execute("SELECT * from \"books\""))
+ end
+ end
+ end
+
+ def db_migrate_and_status(expected_database)
+ rails "generate", "model", "book", "title:string"
+ rails "db:migrate"
+ output = rails("db:migrate:status")
+ assert_match(%r{database:\s+\S*#{Regexp.escape(expected_database)}}, output)
+ assert_match(/up\s+\d{14}\s+Create books/, output)
+ end
+
+ test "db:migrate and db:migrate:status without database_url" do
require "#{app_path}/config/environment"
- db_migrate_and_status ActiveRecord::Base.configurations[Rails.env]['database']
+ db_migrate_and_status ActiveRecord::Base.configurations[Rails.env]["database"]
end
- test 'db:migrate and db:migrate:status with database_url' do
+ test "db:migrate and db:migrate:status with database_url" do
require "#{app_path}/config/environment"
set_database_url
db_migrate_and_status database_url_db_name
@@ -124,170 +260,177 @@ module ApplicationTests
def db_schema_dump
Dir.chdir(app_path) do
- `bin/rails generate model book title:string;
- bin/rails db:migrate db:schema:dump`
+ rails "generate", "model", "book", "title:string"
+ rails "db:migrate", "db:schema:dump"
schema_dump = File.read("db/schema.rb")
assert_match(/create_table \"books\"/, schema_dump)
end
end
- test 'db:schema:dump without database_url' do
+ test "db:schema:dump without database_url" do
db_schema_dump
end
- test 'db:schema:dump with database_url' do
+ test "db:schema:dump with database_url" do
set_database_url
db_schema_dump
end
def db_fixtures_load(expected_database)
Dir.chdir(app_path) do
- `bin/rails generate model book title:string;
- bin/rails db:migrate db:fixtures:load`
+ 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
- test 'db:fixtures:load without database_url' do
+ test "db:fixtures:load without database_url" do
require "#{app_path}/config/environment"
- db_fixtures_load ActiveRecord::Base.configurations[Rails.env]['database']
+ db_fixtures_load ActiveRecord::Base.configurations[Rails.env]["database"]
end
- test 'db:fixtures:load with database_url' do
+ test "db:fixtures:load with database_url" do
require "#{app_path}/config/environment"
set_database_url
db_fixtures_load database_url_db_name
end
- test 'db:fixtures:load with namespaced fixture' do
+ test "db:fixtures:load with namespaced fixture" do
require "#{app_path}/config/environment"
- Dir.chdir(app_path) do
- `bin/rails generate model admin::book title:string;
- bin/rails db:migrate db:fixtures:load`
- require "#{app_path}/app/models/admin/book"
- assert_equal 2, Admin::Book.count
- end
+
+ rails "generate", "model", "admin::book", "title:string"
+ reload
+ rails "db:migrate", "db:fixtures:load"
+
+ assert_equal 2, Admin::Book.count
end
def db_structure_dump_and_load(expected_database)
Dir.chdir(app_path) do
- `bin/rails generate model book title:string;
- bin/rails db:migrate db:structure:dump`
+ rails "generate", "model", "book", "title:string"
+ rails "db:migrate", "db:structure:dump"
structure_dump = File.read("db/structure.sql")
- assert_match(/CREATE TABLE \"books\"/, structure_dump)
- `bin/rails environment db:drop db:structure:load`
+ assert_match(/CREATE TABLE (?:IF NOT EXISTS )?\"books\"/, structure_dump)
+ rails "environment", "db:drop", "db:structure:load"
assert_match expected_database, ActiveRecord::Base.connection_config[:database]
require "#{app_path}/app/models/book"
- #if structure is not loaded correctly, exception would be raised
+ # if structure is not loaded correctly, exception would be raised
assert_equal 0, Book.count
end
end
- test 'db:structure:dump and db:structure:load without database_url' do
+ test "db:structure:dump and db:structure:load without database_url" do
require "#{app_path}/config/environment"
- db_structure_dump_and_load ActiveRecord::Base.configurations[Rails.env]['database']
+ db_structure_dump_and_load ActiveRecord::Base.configurations[Rails.env]["database"]
end
- test 'db:structure:dump and db:structure:load with database_url' do
+ test "db:structure:dump and db:structure:load with database_url" do
require "#{app_path}/config/environment"
set_database_url
db_structure_dump_and_load database_url_db_name
end
- test 'db:structure:dump does not dump schema information when no migrations are used' do
- Dir.chdir(app_path) do
- # create table without migrations
- `bin/rails runner 'ActiveRecord::Base.connection.create_table(:posts) {|t| t.string :title }'`
+ test "db:structure:dump and db:structure:load set ar_internal_metadata" do
+ require "#{app_path}/config/environment"
+ db_structure_dump_and_load ActiveRecord::Base.configurations[Rails.env]["database"]
- stderr_output = capture(:stderr) { `bin/rails db:structure:dump` }
- assert_empty stderr_output
- structure_dump = File.read("db/structure.sql")
- assert_match(/CREATE TABLE \"posts\"/, structure_dump)
- end
+ assert_equal "test", rails("runner", "-e", "test", "puts ActiveRecord::InternalMetadata[:environment]").strip
+ assert_equal "development", rails("runner", "puts ActiveRecord::InternalMetadata[:environment]").strip
end
- test 'db:schema:load and db:structure:load do not purge the existing database' do
- Dir.chdir(app_path) do
- `bin/rails runner 'ActiveRecord::Base.connection.create_table(:posts) {|t| t.string :title }'`
+ test "db:structure:dump does not dump schema information when no migrations are used" do
+ # create table without migrations
+ rails "runner", "ActiveRecord::Base.connection.create_table(:posts) {|t| t.string :title }"
- app_file 'db/schema.rb', <<-RUBY
- ActiveRecord::Schema.define(version: 20140423102712) do
- create_table(:comments) {}
- end
- RUBY
+ stderr_output = capture(:stderr) { rails("db:structure:dump", stderr: true, allow_failure: true) }
+ assert_empty stderr_output
+ structure_dump = File.read("#{app_path}/db/structure.sql")
+ assert_match(/CREATE TABLE (?:IF NOT EXISTS )?\"posts\"/, structure_dump)
+ end
- list_tables = lambda { `bin/rails runner 'p ActiveRecord::Base.connection.tables'`.strip }
+ test "db:schema:load and db:structure:load do not purge the existing database" do
+ rails "runner", "ActiveRecord::Base.connection.create_table(:posts) {|t| t.string :title }"
- assert_equal '["posts"]', list_tables[]
- `bin/rails db:schema:load`
- assert_equal '["posts", "comments", "schema_migrations", "ar_internal_metadata"]', list_tables[]
+ app_file "db/schema.rb", <<-RUBY
+ ActiveRecord::Schema.define(version: 20140423102712) do
+ create_table(:comments) {}
+ end
+ RUBY
- app_file 'db/structure.sql', <<-SQL
- CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255));
- SQL
+ list_tables = lambda { rails("runner", "p ActiveRecord::Base.connection.tables").strip }
- `bin/rails db:structure:load`
- assert_equal '["posts", "comments", "schema_migrations", "ar_internal_metadata", "users"]', list_tables[]
- end
+ assert_equal '["posts"]', list_tables[]
+ rails "db:schema:load"
+ assert_equal '["posts", "comments", "schema_migrations", "ar_internal_metadata"]', list_tables[]
+
+ app_file "db/structure.sql", <<-SQL
+ CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255));
+ SQL
+
+ rails "db:structure:load"
+ assert_equal '["posts", "comments", "schema_migrations", "ar_internal_metadata", "users"]', list_tables[]
end
test "db:schema:load with inflections" do
- Dir.chdir(app_path) do
- app_file 'config/initializers/inflection.rb', <<-RUBY
- ActiveSupport::Inflector.inflections do |inflect|
- inflect.irregular 'goose', 'geese'
- end
- RUBY
- app_file 'config/initializers/primary_key_table_name.rb', <<-RUBY
- ActiveRecord::Base.primary_key_prefix_type = :table_name
- RUBY
- app_file 'db/schema.rb', <<-RUBY
- ActiveRecord::Schema.define(version: 20140423102712) do
- create_table("goose".pluralize) do |t|
- t.string :name
- end
+ app_file "config/initializers/inflection.rb", <<-RUBY
+ ActiveSupport::Inflector.inflections do |inflect|
+ inflect.irregular 'goose', 'geese'
+ end
+ RUBY
+ app_file "config/initializers/primary_key_table_name.rb", <<-RUBY
+ ActiveRecord::Base.primary_key_prefix_type = :table_name
+ RUBY
+ app_file "db/schema.rb", <<-RUBY
+ ActiveRecord::Schema.define(version: 20140423102712) do
+ create_table("goose".pluralize) do |t|
+ t.string :name
end
- RUBY
+ end
+ RUBY
- `bin/rails db:schema:load`
+ rails "db:schema:load"
- tables = `bin/rails runner 'p ActiveRecord::Base.connection.tables'`.strip
- assert_match(/"geese"/, tables)
+ tables = rails("runner", "p ActiveRecord::Base.connection.tables").strip
+ assert_match(/"geese"/, tables)
- columns = `bin/rails runner 'p ActiveRecord::Base.connection.columns("geese").map(&:name)'`.strip
- assert_equal columns, '["gooseid", "name"]'
- end
+ columns = rails("runner", "p ActiveRecord::Base.connection.columns('geese').map(&:name)").strip
+ assert_equal columns, '["gooseid", "name"]'
+ end
+
+ test "db:schema:load fails if schema.rb doesn't exist yet" do
+ stderr_output = capture(:stderr) { rails("db:schema:load", stderr: true, allow_failure: true) }
+ assert_match(/Run `rails db:migrate` to create it/, stderr_output)
end
def db_test_load_structure
Dir.chdir(app_path) do
- `bin/rails generate model book title:string;
- bin/rails db:migrate db:structure:dump db:test:load_structure`
+ rails "generate", "model", "book", "title:string"
+ rails "db:migrate", "db:structure:dump", "db:test:load_structure"
ActiveRecord::Base.configurations = Rails.application.config.database_configuration
ActiveRecord::Base.establish_connection :test
require "#{app_path}/app/models/book"
- #if structure is not loaded correctly, exception would be raised
+ # if structure is not loaded correctly, exception would be raised
assert_equal 0, Book.count
- assert_match ActiveRecord::Base.configurations['test']['database'],
+ assert_match ActiveRecord::Base.configurations["test"]["database"],
ActiveRecord::Base.connection_config[:database]
end
end
- test 'db:test:load_structure without database_url' do
+ test "db:test:load_structure without database_url" do
require "#{app_path}/config/environment"
db_test_load_structure
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"
+ test "db:setup loads schema and seeds database" do
+ @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
@@ -295,17 +438,135 @@ module ApplicationTests
end
RUBY
- app_file 'db/seeds.rb', <<-RUBY
- puts ActiveRecord::Base.connection_config[:database]
+ 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
+
+ test "db:setup sets ar_internal_metadata" do
+ app_file "db/schema.rb", ""
+ rails "db:setup"
+
+ test_environment = lambda { rails("runner", "-e", "test", "puts ActiveRecord::InternalMetadata[:environment]").strip }
+ development_environment = lambda { rails("runner", "puts ActiveRecord::InternalMetadata[:environment]").strip }
+
+ assert_equal "test", test_environment.call
+ assert_equal "development", development_environment.call
+
+ app_file "db/structure.sql", ""
+ app_file "config/initializers/enable_sql_schema_format.rb", <<-RUBY
+ Rails.application.config.active_record.schema_format = :sql
+ RUBY
+
+ rails "db:setup"
+
+ assert_equal "test", test_environment.call
+ assert_equal "development", development_environment.call
+ end
+
+ test "db:test:prepare sets test ar_internal_metadata" do
+ app_file "db/schema.rb", ""
+ rails "db:test:prepare"
+
+ test_environment = lambda { rails("runner", "-e", "test", "puts ActiveRecord::InternalMetadata[:environment]").strip }
+
+ assert_equal "test", test_environment.call
+
+ app_file "db/structure.sql", ""
+ app_file "config/initializers/enable_sql_schema_format.rb", <<-RUBY
+ Rails.application.config.active_record.schema_format = :sql
+ RUBY
+
+ rails "db:test:prepare"
+
+ assert_equal "test", test_environment.call
+ end
+
+ test "db:seed:replant truncates all non-internal tables and loads the seeds" do
+ Dir.chdir(app_path) do
+ rails "generate", "model", "book", "title:string"
+ rails "db:migrate"
+ require "#{app_path}/config/environment"
+ Book.create!(title: "Remote")
+ assert_equal 1, Book.count
+ schema_migrations = ActiveRecord::Base.connection.execute("SELECT * from \"#{ActiveRecord::Base.schema_migrations_table_name}\"")
+ internal_metadata = ActiveRecord::Base.connection.execute("SELECT * from \"#{ActiveRecord::Base.internal_metadata_table_name}\"")
+
+ app_file "db/seeds.rb", <<-RUBY
+ Book.create!(title: "Rework")
+ Book.create!(title: "Ruby Under a Microscope")
RUBY
+ rails "db:seed:replant"
+
+ assert_equal(
+ schema_migrations,
+ ActiveRecord::Base.connection.execute("SELECT * from \"#{ActiveRecord::Base.schema_migrations_table_name}\"")
+ )
+ assert_equal(
+ internal_metadata,
+ ActiveRecord::Base.connection.execute("SELECT * from \"#{ActiveRecord::Base.internal_metadata_table_name}\"")
+ )
+ assert_equal 2, Book.count
+ assert_not_predicate Book.where(title: "Remote"), :exists?
+ assert_predicate Book.where(title: "Rework"), :exists?
+ assert_predicate Book.where(title: "Ruby Under a Microscope"), :exists?
+ end
+ end
+
+ test "db:seed:replant does not truncate any tables and does not load the seeds when environment is protected" do
+ with_rails_env "production" do
Dir.chdir(app_path) do
- database_path = `bin/rails db:setup`
- assert_equal "development.sqlite3", File.basename(database_path.strip)
+ rails "generate", "model", "book", "title:string"
+ rails "db:migrate"
+ require "#{app_path}/config/environment"
+ Book.create!(title: "Remote")
+ assert_equal 1, Book.count
+ schema_migrations = ActiveRecord::Base.connection.execute("SELECT * from \"#{ActiveRecord::Base.schema_migrations_table_name}\"")
+ internal_metadata = ActiveRecord::Base.connection.execute("SELECT * from \"#{ActiveRecord::Base.internal_metadata_table_name}\"")
+ books = ActiveRecord::Base.connection.execute("SELECT * from \"books\"")
+
+ app_file "db/seeds.rb", <<-RUBY
+ Book.create!(title: "Rework")
+ RUBY
+
+ output = rails("db:seed:replant", allow_failure: true)
+ assert_match(/ActiveRecord::ProtectedEnvironmentError/, output)
+
+ assert_equal(
+ schema_migrations,
+ ActiveRecord::Base.connection.execute("SELECT * from \"#{ActiveRecord::Base.schema_migrations_table_name}\"")
+ )
+ assert_equal(
+ internal_metadata,
+ ActiveRecord::Base.connection.execute("SELECT * from \"#{ActiveRecord::Base.internal_metadata_table_name}\"")
+ )
+ assert_equal 1, Book.count
+ assert_equal(books, ActiveRecord::Base.connection.execute("SELECT * from \"books\""))
+ assert_not_predicate Book.where(title: "Rework"), :exists?
end
- ensure
- ENV["RAILS_ENV"] = @old_rails_env
- ENV["RACK_ENV"] = @old_rack_env
+ end
+ end
+
+ test "db:prepare setup the database" do
+ Dir.chdir(app_path) do
+ rails "generate", "model", "book", "title:string"
+ output = rails("db:prepare")
+ assert_match(/CreateBooks: migrated/, output)
+
+ output = rails("db:drop")
+ assert_match(/Dropped database/, output)
+
+ rails "generate", "model", "recipe", "title:string"
+ output = rails("db:prepare")
+ assert_match(/CreateBooks: migrated/, output)
+ assert_match(/CreateRecipes: migrated/, output)
end
end
end
diff --git a/railties/test/application/rake/dev_test.rb b/railties/test/application/rake/dev_test.rb
index deb9bc8dee..a87f453075 100644
--- a/railties/test/application/rake/dev_test.rb
+++ b/railties/test/application/rake/dev_test.rb
@@ -1,4 +1,6 @@
-require 'isolation/abstract_unit'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
module ApplicationTests
module RakeTests
@@ -7,37 +9,55 @@ module ApplicationTests
def setup
build_app
+ add_to_env_config("development", "config.active_support.deprecation = :stderr")
end
def teardown
teardown_app
end
- test 'dev:cache creates file and outputs message' do
+ test "dev:cache creates file and outputs message" do
Dir.chdir(app_path) do
- output = `rails dev:cache`
- assert File.exist?('tmp/caching-dev.txt')
- assert_match(/Development mode is now being cached/, output)
+ stderr = capture(:stderr) do
+ output = run_rake_dev_cache
+ assert File.exist?("tmp/caching-dev.txt")
+ assert_match(/Development mode is now being cached/, output)
+ end
+ assert_match(/DEPRECATION WARNING: Using `bin\/rake dev:cache` is deprecated and will be removed in Rails 6.1/, stderr)
end
end
- test 'dev:cache deletes file and outputs message' do
+ test "dev:cache deletes file and outputs message" do
Dir.chdir(app_path) do
- `rails dev:cache` # Create caching file.
- output = `rails dev:cache` # Delete caching file.
- assert_not File.exist?('tmp/caching-dev.txt')
- assert_match(/Development mode is no longer being cached/, output)
+ stderr = capture(:stderr) do
+ run_rake_dev_cache # Create caching file.
+ output = run_rake_dev_cache # Delete caching file.
+ assert_not File.exist?("tmp/caching-dev.txt")
+ assert_match(/Development mode is no longer being cached/, output)
+ end
+ assert_match(/DEPRECATION WARNING: Using `bin\/rake dev:cache` is deprecated and will be removed in Rails 6.1/, stderr)
end
end
- test 'dev:cache removes server.pid also' do
+ test "dev:cache touches tmp/restart.txt" do
Dir.chdir(app_path) do
- FileUtils.mkdir_p("tmp/pids")
- FileUtils.touch("tmp/pids/server.pid")
- `rake dev:cache`
- assert_not File.exist?("tmp/pids/server.pid")
+ stderr = capture(:stderr) do
+ run_rake_dev_cache
+ assert File.exist?("tmp/restart.txt")
+
+ prev_mtime = File.mtime("tmp/restart.txt")
+ run_rake_dev_cache
+ curr_mtime = File.mtime("tmp/restart.txt")
+ assert_not_equal prev_mtime, curr_mtime
+ end
+ assert_match(/DEPRECATION WARNING: Using `bin\/rake dev:cache` is deprecated and will be removed in Rails 6.1/, stderr)
end
end
+
+ private
+ def run_rake_dev_cache
+ `bin/rake dev:cache`
+ end
end
end
end
diff --git a/railties/test/application/rake/framework_test.rb b/railties/test/application/rake/framework_test.rb
index ec57af79f6..644b1924b5 100644
--- a/railties/test/application/rake/framework_test.rb
+++ b/railties/test/application/rake/framework_test.rb
@@ -1,5 +1,6 @@
+# frozen_string_literal: true
+
require "isolation/abstract_unit"
-require "active_support/core_ext/string/strip"
module ApplicationTests
module RakeTests
@@ -8,7 +9,6 @@ module ApplicationTests
def setup
build_app
- boot_rails
FileUtils.rm_rf("#{app_path}/config/environments")
end
@@ -17,14 +17,14 @@ module ApplicationTests
end
def load_tasks
- require 'rake'
- require 'rdoc/task'
- require 'rake/testtask'
+ require "rake"
+ require "rdoc/task"
+ require "rake/testtask"
Rails.application.load_tasks
end
- test 'requiring the rake task should not define method .app_generator on Object' do
+ test "requiring the rake task should not define method .app_generator on Object" do
require "#{app_path}/config/environment"
load_tasks
@@ -34,7 +34,7 @@ module ApplicationTests
end
end
- test 'requiring the rake task should not define method .invoke_from_app_generator on Object' do
+ test "requiring the rake task should not define method .invoke_from_app_generator on Object" do
require "#{app_path}/config/environment"
load_tasks
diff --git a/railties/test/application/rake/initializers_test.rb b/railties/test/application/rake/initializers_test.rb
new file mode 100644
index 0000000000..8de4967021
--- /dev/null
+++ b/railties/test/application/rake/initializers_test.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+
+module ApplicationTests
+ module RakeTests
+ class RakeInitializersTest < ActiveSupport::TestCase
+ setup :build_app
+ teardown :teardown_app
+
+ test "`rake initializers` prints out defined initializers invoked by Rails" do
+ capture(:stderr) do
+ initial_output = run_rake_initializers
+ initial_output_length = initial_output.split("\n").length
+
+ assert_operator initial_output_length, :>, 0
+ assert_not initial_output.include?("set_added_test_module")
+
+ add_to_config <<-RUBY
+ initializer(:set_added_test_module) { }
+ RUBY
+
+ final_output = run_rake_initializers
+ final_output_length = final_output.split("\n").length
+
+ assert_equal 1, (final_output_length - initial_output_length)
+ assert final_output.include?("set_added_test_module")
+ end
+ end
+
+ test "`rake initializers` outputs a deprecation warning" do
+ add_to_env_config("development", "config.active_support.deprecation = :stderr")
+
+ stderr = capture(:stderr) { run_rake_initializers }
+ assert_match(/DEPRECATION WARNING: Using `bin\/rake initializers` is deprecated and will be removed in Rails 6.1/, stderr)
+ end
+
+ private
+ def run_rake_initializers
+ Dir.chdir(app_path) { `bin/rake initializers` }
+ end
+ end
+ end
+end
diff --git a/railties/test/application/rake/log_test.rb b/railties/test/application/rake/log_test.rb
new file mode 100644
index 0000000000..678f26db26
--- /dev/null
+++ b/railties/test/application/rake/log_test.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+
+module ApplicationTests
+ module RakeTests
+ class LogTest < ActiveSupport::TestCase
+ include ActiveSupport::Testing::Isolation
+
+ def setup
+ build_app
+ end
+
+ def teardown
+ teardown_app
+ end
+
+ test "log:clear clear all environments log files by default" do
+ Dir.chdir(app_path) do
+ File.open("config/environments/staging.rb", "w")
+
+ File.write("log/staging.log", "staging")
+ File.write("log/test.log", "test")
+ File.write("log/dummy.log", "dummy")
+
+ rails "log:clear"
+
+ assert_equal 0, File.size("log/test.log")
+ assert_equal 0, File.size("log/staging.log")
+ assert_equal 5, File.size("log/dummy.log")
+ end
+ end
+ end
+ end
+end
diff --git a/railties/test/application/rake/migrations_test.rb b/railties/test/application/rake/migrations_test.rb
index 7e2519ae5a..47c5ac105a 100644
--- a/railties/test/application/rake/migrations_test.rb
+++ b/railties/test/application/rake/migrations_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "isolation/abstract_unit"
module ApplicationTests
@@ -5,7 +7,6 @@ module ApplicationTests
class RakeMigrationsTest < ActiveSupport::TestCase
def setup
build_app
- boot_rails
FileUtils.rm_rf("#{app_path}/config/environments")
end
@@ -13,211 +14,441 @@ module ApplicationTests
teardown_app
end
- test 'running migrations with given scope' do
- Dir.chdir(app_path) do
- `bin/rails generate model user username:string password:string`
+ test "running migrations with given scope" do
+ rails "generate", "model", "user", "username:string", "password:string"
- app_file "db/migrate/01_a_migration.bukkits.rb", <<-MIGRATION
- class AMigration < ActiveRecord::Migration::Current
- end
- MIGRATION
+ app_file "db/migrate/01_a_migration.bukkits.rb", <<-MIGRATION
+ class AMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
- output = `bin/rails db:migrate SCOPE=bukkits`
- assert_no_match(/create_table\(:users\)/, output)
- assert_no_match(/CreateUsers/, output)
- assert_no_match(/add_column\(:users, :email, :string\)/, output)
+ output = rails("db:migrate", "SCOPE=bukkits")
+ assert_no_match(/create_table\(:users\)/, output)
+ assert_no_match(/CreateUsers/, output)
+ assert_no_match(/add_column\(:users, :email, :string\)/, output)
- assert_match(/AMigration: migrated/, output)
+ assert_match(/AMigration: migrated/, output)
- output = `bin/rails db:migrate SCOPE=bukkits VERSION=0`
- assert_no_match(/drop_table\(:users\)/, output)
- assert_no_match(/CreateUsers/, output)
- assert_no_match(/remove_column\(:users, :email\)/, output)
+ # run all the migrations to test scope for down
+ output = rails("db:migrate")
+ assert_match(/CreateUsers: migrated/, output)
- assert_match(/AMigration: reverted/, output)
- end
+ output = rails("db:migrate", "SCOPE=bukkits", "VERSION=0")
+ assert_no_match(/drop_table\(:users\)/, output)
+ assert_no_match(/CreateUsers/, output)
+ assert_no_match(/remove_column\(:users, :email\)/, output)
+
+ assert_match(/AMigration: reverted/, output)
+
+ output = rails("db:migrate", "VERSION=0")
+
+ assert_match(/CreateUsers: reverted/, output)
end
- test 'model and migration generator with change syntax' do
- Dir.chdir(app_path) do
- `bin/rails generate model user username:string password:string;
- bin/rails generate migration add_email_to_users email:string`
-
- output = `bin/rails db:migrate`
- assert_match(/create_table\(:users\)/, output)
- assert_match(/CreateUsers: migrated/, output)
- assert_match(/add_column\(:users, :email, :string\)/, output)
- assert_match(/AddEmailToUsers: migrated/, output)
-
- output = `bin/rails db:rollback STEP=2`
- assert_match(/drop_table\(:users\)/, output)
- assert_match(/CreateUsers: reverted/, output)
- assert_match(/remove_column\(:users, :email, :string\)/, output)
- assert_match(/AddEmailToUsers: reverted/, output)
- end
+ test "version outputs current version" do
+ app_file "db/migrate/01_one_migration.rb", <<-MIGRATION
+ class OneMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ rails "db:migrate"
+
+ output = rails("db:version")
+ assert_match(/Current version: 1/, output)
end
- test 'migration status when schema migrations table is not present' do
- output = Dir.chdir(app_path){ `bin/rails db:migrate:status 2>&1` }
+ test "migrate with specified VERSION in different formats" do
+ app_file "db/migrate/01_one_migration.rb", <<-MIGRATION
+ class OneMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ app_file "db/migrate/02_two_migration.rb", <<-MIGRATION
+ class TwoMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ app_file "db/migrate/03_three_migration.rb", <<-MIGRATION
+ class ThreeMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ rails "db:migrate"
+
+ output = rails("db:migrate:status")
+ assert_match(/up\s+001\s+One migration/, output)
+ assert_match(/up\s+002\s+Two migration/, output)
+ assert_match(/up\s+003\s+Three migration/, output)
+
+ rails "db:migrate", "VERSION=01_one_migration.rb"
+ output = rails("db:migrate:status")
+ assert_match(/up\s+001\s+One migration/, output)
+ assert_match(/down\s+002\s+Two migration/, output)
+ assert_match(/down\s+003\s+Three migration/, output)
+
+ rails "db:migrate", "VERSION=3"
+ output = rails("db:migrate:status")
+ assert_match(/up\s+001\s+One migration/, output)
+ assert_match(/up\s+002\s+Two migration/, output)
+ assert_match(/up\s+003\s+Three migration/, output)
+
+ rails "db:migrate", "VERSION=001"
+ output = rails("db:migrate:status")
+ assert_match(/up\s+001\s+One migration/, output)
+ assert_match(/down\s+002\s+Two migration/, output)
+ assert_match(/down\s+003\s+Three migration/, output)
+ end
+
+ test "migration with empty version" do
+ app_file "db/migrate/01_one_migration.rb", <<-MIGRATION
+ class OneMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ app_file "db/migrate/02_two_migration.rb", <<-MIGRATION
+ class TwoMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ rails("db:migrate", "VERSION=")
+
+ output = rails("db:migrate:status")
+ assert_match(/up\s+001\s+One migration/, output)
+ assert_match(/up\s+002\s+Two migration/, output)
+
+ output = rails("db:migrate:redo", "VERSION=", allow_failure: true)
+ assert_match(/Empty VERSION provided/, output)
+
+ output = rails("db:migrate:up", "VERSION=", allow_failure: true)
+ assert_match(/VERSION is required/, output)
+
+ output = rails("db:migrate:up", allow_failure: true)
+ assert_match(/VERSION is required/, output)
+
+ output = rails("db:migrate:down", "VERSION=", allow_failure: true)
+ assert_match(/VERSION is required - To go down one migration, use db:rollback/, output)
+
+ output = rails("db:migrate:down", allow_failure: true)
+ assert_match(/VERSION is required - To go down one migration, use db:rollback/, output)
+
+ output = rails("db:migrate:status")
+ assert_match(/up\s+001\s+One migration/, output)
+ assert_match(/up\s+002\s+Two migration/, output)
+ end
+
+ test "migration with 0 version" do
+ app_file "db/migrate/01_one_migration.rb", <<-MIGRATION
+ class OneMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ app_file "db/migrate/02_two_migration.rb", <<-MIGRATION
+ class TwoMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ rails "db:migrate"
+
+ output = rails("db:migrate:status")
+ assert_match(/up\s+001\s+One migration/, output)
+ assert_match(/up\s+002\s+Two migration/, output)
+
+ rails "db:migrate", "VERSION=0"
+
+ output = rails("db:migrate:status")
+ assert_match(/down\s+001\s+One migration/, output)
+ assert_match(/down\s+002\s+Two migration/, output)
+ end
+
+ test "model and migration generator with change syntax" do
+ rails "generate", "model", "user", "username:string", "password:string"
+ rails "generate", "migration", "add_email_to_users", "email:string"
+
+ output = rails("db:migrate")
+ assert_match(/create_table\(:users\)/, output)
+ assert_match(/CreateUsers: migrated/, output)
+ assert_match(/add_column\(:users, :email, :string\)/, output)
+ assert_match(/AddEmailToUsers: migrated/, output)
+
+ output = rails("db:rollback", "STEP=2")
+ assert_match(/drop_table\(:users\)/, output)
+ assert_match(/CreateUsers: reverted/, output)
+ assert_match(/remove_column\(:users, :email, :string\)/, output)
+ assert_match(/AddEmailToUsers: reverted/, output)
+ end
+
+ test "migration status when schema migrations table is not present" do
+ output = rails("db:migrate:status", allow_failure: true)
assert_equal "Schema migrations table does not exist yet.\n", output
end
- test 'test migration status' do
+ test "migration status" do
+ rails "generate", "model", "user", "username:string", "password:string"
+ rails "generate", "migration", "add_email_to_users", "email:string"
+ rails "db:migrate"
+
+ output = rails("db:migrate:status")
+
+ assert_match(/up\s+\d{14}\s+Create users/, output)
+ assert_match(/up\s+\d{14}\s+Add email to users/, output)
+
+ rails "db:rollback", "STEP=1"
+ output = rails("db:migrate:status")
+
+ assert_match(/up\s+\d{14}\s+Create users/, output)
+ assert_match(/down\s+\d{14}\s+Add email to users/, output)
+ end
+
+ test "migration status without timestamps" do
+ add_to_config("config.active_record.timestamped_migrations = false")
+
+ rails "generate", "model", "user", "username:string", "password:string"
+ rails "generate", "migration", "add_email_to_users", "email:string"
+ rails "db:migrate"
+
+ output = rails("db:migrate:status")
+
+ assert_match(/up\s+\d{3,}\s+Create users/, output)
+ assert_match(/up\s+\d{3,}\s+Add email to users/, output)
+
+ rails "db:rollback", "STEP=1"
+ output = rails("db:migrate:status")
+
+ assert_match(/up\s+\d{3,}\s+Create users/, output)
+ assert_match(/down\s+\d{3,}\s+Add email to users/, output)
+ end
+
+ test "migration status after rollback and redo" do
+ rails "generate", "model", "user", "username:string", "password:string"
+ rails "generate", "migration", "add_email_to_users", "email:string"
+ rails "db:migrate"
+
+ output = rails("db:migrate:status")
+
+ assert_match(/up\s+\d{14}\s+Create users/, output)
+ assert_match(/up\s+\d{14}\s+Add email to users/, output)
+
+ rails "db:rollback", "STEP=2"
+ output = rails("db:migrate:status")
+
+ assert_match(/down\s+\d{14}\s+Create users/, output)
+ assert_match(/down\s+\d{14}\s+Add email to users/, output)
+
+ rails "db:migrate:redo"
+ output = rails("db:migrate:status")
+
+ assert_match(/up\s+\d{14}\s+Create users/, output)
+ assert_match(/up\s+\d{14}\s+Add email to users/, output)
+ end
+
+ test "migration status after rollback and forward" do
+ rails "generate", "model", "user", "username:string", "password:string"
+ rails "generate", "migration", "add_email_to_users", "email:string"
+ rails "db:migrate"
+
+ output = rails("db:migrate:status")
+
+ assert_match(/up\s+\d{14}\s+Create users/, output)
+ assert_match(/up\s+\d{14}\s+Add email to users/, output)
+
+ rails "db:rollback", "STEP=2"
+ output = rails("db:migrate:status")
+
+ assert_match(/down\s+\d{14}\s+Create users/, output)
+ assert_match(/down\s+\d{14}\s+Add email to users/, output)
+
+ rails "db:forward", "STEP=2"
+ output = rails("db:migrate:status")
+
+ assert_match(/up\s+\d{14}\s+Create users/, output)
+ assert_match(/up\s+\d{14}\s+Add email to users/, output)
+ end
+
+ test "raise error on any move when current migration does not exist" do
Dir.chdir(app_path) do
- `bin/rails generate model user username:string password:string;
- bin/rails generate migration add_email_to_users email:string;
- bin/rails db:migrate`
+ rails "generate", "model", "user", "username:string", "password:string"
+ rails "generate", "migration", "add_email_to_users", "email:string"
+ rails "db:migrate"
+ `rm db/migrate/*email*.rb`
+
+ output = rails("db:migrate:status")
+ assert_match(/up\s+\d{14}\s+Create users/, output)
+ assert_match(/up\s+\d{14}\s+\** NO FILE \**/, output)
- output = `bin/rails db:migrate:status`
+ output = rails("db:rollback", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/ActiveRecord::UnknownMigrationVersionError:/, output)
+ assert_match(/No migration with version number\s\d{14}\./, output)
+ output = rails("db:migrate:status")
assert_match(/up\s+\d{14}\s+Create users/, output)
- assert_match(/up\s+\d{14}\s+Add email to users/, output)
+ assert_match(/up\s+\d{14}\s+\** NO FILE \**/, output)
- `bin/rails db:rollback STEP=1`
- output = `bin/rails db:migrate:status`
+ output = rails("db:forward", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/ActiveRecord::UnknownMigrationVersionError:/, output)
+ assert_match(/No migration with version number\s\d{14}\./, output)
+ output = rails("db:migrate:status")
assert_match(/up\s+\d{14}\s+Create users/, output)
- assert_match(/down\s+\d{14}\s+Add email to users/, output)
+ assert_match(/up\s+\d{14}\s+\** NO FILE \**/, output)
end
end
- test 'migration status without timestamps' do
- add_to_config('config.active_record.timestamped_migrations = false')
+ test "raise error on any move when target migration does not exist" do
+ app_file "db/migrate/01_one_migration.rb", <<-MIGRATION
+ class OneMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
- Dir.chdir(app_path) do
- `bin/rails generate model user username:string password:string;
- bin/rails generate migration add_email_to_users email:string;
- bin/rails db:migrate`
+ app_file "db/migrate/02_two_migration.rb", <<-MIGRATION
+ class TwoMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
- output = `bin/rails db:migrate:status`
+ rails "db:migrate"
- assert_match(/up\s+\d{3,}\s+Create users/, output)
- assert_match(/up\s+\d{3,}\s+Add email to users/, output)
+ output = rails("db:migrate:status")
+ assert_match(/up\s+001\s+One migration/, output)
+ assert_match(/up\s+002\s+Two migration/, output)
- `bin/rails db:rollback STEP=1`
- output = `bin/rails db:migrate:status`
+ output = rails("db:migrate", "VERSION=3", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/ActiveRecord::UnknownMigrationVersionError:/, output)
+ assert_match(/No migration with version number 3/, output)
- assert_match(/up\s+\d{3,}\s+Create users/, output)
- assert_match(/down\s+\d{3,}\s+Add email to users/, output)
- end
+ output = rails("db:migrate:status")
+ assert_match(/up\s+001\s+One migration/, output)
+ assert_match(/up\s+002\s+Two migration/, output)
end
- test 'test migration status after rollback and redo' do
- Dir.chdir(app_path) do
- `bin/rails generate model user username:string password:string;
- bin/rails generate migration add_email_to_users email:string;
- bin/rails db:migrate`
+ test "raise error on any move when VERSION has invalid format" do
+ output = rails("db:migrate", "VERSION=unknown", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
- output = `bin/rails db:migrate:status`
+ output = rails("db:migrate", "VERSION=0.1.11", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
- assert_match(/up\s+\d{14}\s+Create users/, output)
- assert_match(/up\s+\d{14}\s+Add email to users/, output)
+ output = rails("db:migrate", "VERSION=1.1.11", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
- `bin/rails db:rollback STEP=2`
- output = `bin/rails db:migrate:status`
+ output = rails("db:migrate", "VERSION='0 '", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
- assert_match(/down\s+\d{14}\s+Create users/, output)
- assert_match(/down\s+\d{14}\s+Add email to users/, output)
+ output = rails("db:migrate", "VERSION=1.", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
- `bin/rails db:migrate:redo`
- output = `bin/rails db:migrate:status`
+ output = rails("db:migrate", "VERSION=1_", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
- assert_match(/up\s+\d{14}\s+Create users/, output)
- assert_match(/up\s+\d{14}\s+Add email to users/, output)
- end
+ output = rails("db:migrate", "VERSION=1_name", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
+
+ output = rails("db:migrate:redo", "VERSION=unknown", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
+
+ output = rails("db:migrate:up", "VERSION=unknown", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
+
+ output = rails("db:migrate:down", "VERSION=unknown", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
end
- test 'migration status after rollback and redo without timestamps' do
- add_to_config('config.active_record.timestamped_migrations = false')
+ test "migration status after rollback and redo without timestamps" do
+ add_to_config("config.active_record.timestamped_migrations = false")
- Dir.chdir(app_path) do
- `bin/rails generate model user username:string password:string;
- bin/rails generate migration add_email_to_users email:string;
- bin/rails db:migrate`
+ rails "generate", "model", "user", "username:string", "password:string"
+ rails "generate", "migration", "add_email_to_users", "email:string"
+ rails "db:migrate"
- output = `bin/rails db:migrate:status`
+ output = rails("db:migrate:status")
- assert_match(/up\s+\d{3,}\s+Create users/, output)
- assert_match(/up\s+\d{3,}\s+Add email to users/, output)
+ assert_match(/up\s+\d{3,}\s+Create users/, output)
+ assert_match(/up\s+\d{3,}\s+Add email to users/, output)
- `bin/rails db:rollback STEP=2`
- output = `bin/rails db:migrate:status`
+ rails "db:rollback", "STEP=2"
+ output = rails("db:migrate:status")
- assert_match(/down\s+\d{3,}\s+Create users/, output)
- assert_match(/down\s+\d{3,}\s+Add email to users/, output)
+ assert_match(/down\s+\d{3,}\s+Create users/, output)
+ assert_match(/down\s+\d{3,}\s+Add email to users/, output)
- `bin/rails db:migrate:redo`
- output = `bin/rails db:migrate:status`
+ rails "db:migrate:redo"
+ output = rails("db:migrate:status")
- assert_match(/up\s+\d{3,}\s+Create users/, output)
- assert_match(/up\s+\d{3,}\s+Add email to users/, output)
- end
+ assert_match(/up\s+\d{3,}\s+Create users/, output)
+ assert_match(/up\s+\d{3,}\s+Add email to users/, output)
end
- test 'running migrations with not timestamp head migration files' do
- Dir.chdir(app_path) do
-
- app_file "db/migrate/1_one_migration.rb", <<-MIGRATION
- class OneMigration < ActiveRecord::Migration::Current
- end
- MIGRATION
+ test "running migrations with not timestamp head migration files" do
+ app_file "db/migrate/1_one_migration.rb", <<-MIGRATION
+ class OneMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
- app_file "db/migrate/02_two_migration.rb", <<-MIGRATION
- class TwoMigration < ActiveRecord::Migration::Current
- end
- MIGRATION
+ app_file "db/migrate/02_two_migration.rb", <<-MIGRATION
+ class TwoMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
- `bin/rails db:migrate`
+ rails "db:migrate"
- output = `bin/rails db:migrate:status`
+ output = rails("db:migrate:status")
- assert_match(/up\s+001\s+One migration/, output)
- assert_match(/up\s+002\s+Two migration/, output)
- end
+ assert_match(/up\s+001\s+One migration/, output)
+ assert_match(/up\s+002\s+Two migration/, output)
end
- test 'schema generation when dump_schema_after_migration is set' do
- add_to_config('config.active_record.dump_schema_after_migration = false')
+ test "schema generation when dump_schema_after_migration is set" do
+ add_to_config("config.active_record.dump_schema_after_migration = false")
Dir.chdir(app_path) do
- `bin/rails generate model book title:string`
- output = `bin/rails generate model author name:string`
+ rails "generate", "model", "book", "title:string"
+ output = rails("generate", "model", "author", "name:string")
version = output =~ %r{[^/]+db/migrate/(\d+)_create_authors\.rb} && $1
- `bin/rails db:migrate db:rollback db:forward db:migrate:up db:migrate:down VERSION=#{version}`
- assert !File.exist?("db/schema.rb"), "should not dump schema when configured not to"
+ rails "db:migrate", "db:rollback", "db:forward", "db:migrate:up", "db:migrate:down", "VERSION=#{version}"
+ assert_not File.exist?("db/schema.rb"), "should not dump schema when configured not to"
end
- add_to_config('config.active_record.dump_schema_after_migration = true')
+ add_to_config("config.active_record.dump_schema_after_migration = true")
Dir.chdir(app_path) do
- `bin/rails generate model reviews book_id:integer`
- `bin/rails db:migrate`
+ rails "generate", "model", "reviews", "book_id:integer"
+ rails "db:migrate"
structure_dump = File.read("db/schema.rb")
assert_match(/create_table "reviews"/, structure_dump)
end
end
- test 'default schema generation after migration' do
+ test "default schema generation after migration" do
Dir.chdir(app_path) do
- `bin/rails generate model book title:string;
- bin/rails db:migrate`
+ rails "generate", "model", "book", "title:string"
+ rails "db:migrate"
structure_dump = File.read("db/schema.rb")
assert_match(/create_table "books"/, structure_dump)
end
end
- test 'test migration status migrated file is deleted' do
+ test "migration status migrated file is deleted" do
Dir.chdir(app_path) do
- `bin/rails generate model user username:string password:string;
- bin/rails generate migration add_email_to_users email:string;
- bin/rails db:migrate
- rm db/migrate/*email*.rb`
+ rails "generate", "model", "user", "username:string", "password:string"
+ rails "generate", "migration", "add_email_to_users", "email:string"
+ rails "db:migrate"
+ `rm db/migrate/*email*.rb`
- output = `bin/rails db:migrate:status`
- File.write('test.txt', output)
+ output = rails("db:migrate:status")
assert_match(/up\s+\d{14}\s+Create users/, output)
assert_match(/up\s+\d{14}\s+\** NO FILE \**/, output)
diff --git a/railties/test/application/rake/multi_dbs_test.rb b/railties/test/application/rake/multi_dbs_test.rb
new file mode 100644
index 0000000000..147b8f94e1
--- /dev/null
+++ b/railties/test/application/rake/multi_dbs_test.rb
@@ -0,0 +1,251 @@
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+
+module ApplicationTests
+ module RakeTests
+ class RakeMultiDbsTest < ActiveSupport::TestCase
+ include ActiveSupport::Testing::Isolation
+
+ def setup
+ build_app(multi_db: true)
+ FileUtils.rm_rf("#{app_path}/config/environments")
+ end
+
+ def teardown
+ teardown_app
+ end
+
+ def db_create_and_drop(namespace, expected_database)
+ Dir.chdir(app_path) do
+ output = rails("db:create")
+ assert_match(/Created database/, output)
+ assert_match_namespace(namespace, output)
+ assert_no_match(/already exists/, output)
+ assert File.exist?(expected_database)
+
+
+ output = rails("db:drop")
+ assert_match(/Dropped database/, output)
+ assert_match_namespace(namespace, output)
+ assert_no_match(/does not exist/, output)
+ assert_not File.exist?(expected_database)
+ end
+ end
+
+ def db_create_and_drop_namespace(namespace, expected_database)
+ Dir.chdir(app_path) do
+ output = rails("db:create:#{namespace}")
+ assert_match(/Created database/, output)
+ assert_match_namespace(namespace, output)
+ assert File.exist?(expected_database)
+
+ output = rails("db:drop:#{namespace}")
+ assert_match(/Dropped database/, output)
+ assert_match_namespace(namespace, output)
+ assert_not File.exist?(expected_database)
+ end
+ end
+
+ def assert_match_namespace(namespace, output)
+ if namespace == "primary"
+ assert_match(/#{Rails.env}.sqlite3/, output)
+ else
+ assert_match(/#{Rails.env}_#{namespace}.sqlite3/, output)
+ end
+ end
+
+ def db_migrate_and_migrate_status
+ Dir.chdir(app_path) do
+ generate_models_for_animals
+ rails "db:migrate"
+ output = rails "db:migrate:status"
+ assert_match(/up \d+ Create books/, output)
+ assert_match(/up \d+ Create dogs/, output)
+ 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
+ rails "db:migrate", "db:#{format}:dump"
+
+ if format == "schema"
+ schema_dump = File.read("db/#{format}.rb")
+ schema_dump_animals = File.read("db/animals_#{format}.rb")
+ assert_match(/create_table \"books\"/, schema_dump)
+ assert_match(/create_table \"dogs\"/, schema_dump_animals)
+ else
+ schema_dump = File.read("db/#{format}.sql")
+ schema_dump_animals = File.read("db/animals_#{format}.sql")
+ assert_match(/CREATE TABLE (?:IF NOT EXISTS )?\"books\"/, schema_dump)
+ assert_match(/CREATE TABLE (?:IF NOT EXISTS )?\"dogs\"/, schema_dump_animals)
+ end
+
+ rails "db:#{format}:load"
+
+ ar_tables = lambda { rails("runner", "p ActiveRecord::Base.connection.tables").strip }
+ animals_tables = lambda { rails("runner", "p AnimalsBase.connection.tables").strip }
+
+ assert_equal '["schema_migrations", "ar_internal_metadata", "books"]', ar_tables[]
+ assert_equal '["schema_migrations", "ar_internal_metadata", "dogs"]', animals_tables[]
+ end
+ end
+
+ def db_migrate_namespaced(namespace)
+ Dir.chdir(app_path) do
+ generate_models_for_animals
+ output = rails("db:migrate:#{namespace}")
+ if namespace == "primary"
+ assert_match(/CreateBooks: migrated/, output)
+ else
+ assert_match(/CreateDogs: migrated/, output)
+ end
+ end
+ end
+
+ def db_migrate_status_namespaced(namespace)
+ Dir.chdir(app_path) do
+ generate_models_for_animals
+ output = rails("db:migrate:status:#{namespace}")
+ if namespace == "primary"
+ assert_match(/up \d+ Create books/, output)
+ else
+ assert_match(/up \d+ Create dogs/, output)
+ end
+ end
+ end
+
+ def db_prepare
+ Dir.chdir(app_path) do
+ generate_models_for_animals
+ output = rails("db:prepare")
+
+ ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config|
+ if db_config.spec_name == "primary"
+ assert_match(/CreateBooks: migrated/, output)
+ else
+ assert_match(/CreateDogs: migrated/, output)
+ end
+ end
+ end
+ end
+
+ def write_models_for_animals
+ # make a directory for the animals migration
+ FileUtils.mkdir_p("#{app_path}/db/animals_migrate")
+ # move the dogs migration if it unless it already lives there
+ FileUtils.mv(Dir.glob("#{app_path}/db/migrate/**/*dogs.rb").first, "db/animals_migrate/") unless Dir.glob("#{app_path}/db/animals_migrate/**/*dogs.rb").first
+ # delete the dogs migration if it's still present in the
+ # migrate folder. This is necessary because sometimes
+ # the code isn't fast enough and an extra migration gets made
+ FileUtils.rm(Dir.glob("#{app_path}/db/migrate/**/*dogs.rb").first) if Dir.glob("#{app_path}/db/migrate/**/*dogs.rb").first
+
+ # change the base of the dog model
+ app_path("/app/models/dog.rb") do |file_name|
+ file = File.read("#{app_path}/app/models/dog.rb")
+ file.sub!(/ApplicationRecord/, "AnimalsBase")
+ File.write(file_name, file)
+ end
+
+ # create the base model for dog to inherit from
+ File.open("#{app_path}/app/models/animals_base.rb", "w") do |file|
+ file.write(<<~EOS)
+ class AnimalsBase < ActiveRecord::Base
+ self.abstract_class = true
+
+ establish_connection :animals
+ end
+ EOS
+ end
+ end
+
+ def generate_models_for_animals
+ 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
+ require "#{app_path}/config/environment"
+ ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config|
+ db_create_and_drop db_config.spec_name, db_config.config["database"]
+ end
+ end
+
+ test "db:create:namespace and db:drop:namespace works on specified databases" do
+ require "#{app_path}/config/environment"
+ ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config|
+ db_create_and_drop_namespace db_config.spec_name, db_config.config["database"]
+ end
+ end
+
+ test "db:migrate and db:schema:dump and db:schema:load works on all databases" do
+ require "#{app_path}/config/environment"
+ db_migrate_and_schema_dump_and_load "schema"
+ end
+
+ test "db:migrate and db:structure:dump and db:structure:load works on all databases" do
+ require "#{app_path}/config/environment"
+ db_migrate_and_schema_dump_and_load "structure"
+ end
+
+ 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
+ end
+ end
+
+ test "db:migrate:status works on all databases" do
+ require "#{app_path}/config/environment"
+ db_migrate_and_migrate_status
+ end
+
+ 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_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
+
+ test "db:prepare works on all databases" do
+ require "#{app_path}/config/environment"
+ db_prepare
+ end
+ end
+ end
+end
diff --git a/railties/test/application/rake/notes_test.rb b/railties/test/application/rake/notes_test.rb
index 50def9beb0..60802ef7c4 100644
--- a/railties/test/application/rake/notes_test.rb
+++ b/railties/test/application/rake/notes_test.rb
@@ -1,5 +1,7 @@
+# frozen_string_literal: true
+
require "isolation/abstract_unit"
-require 'rails/source_annotation_extractor'
+require "rails/source_annotation_extractor"
module ApplicationTests
module RakeTests
@@ -8,6 +10,7 @@ module ApplicationTests
def setup
build_app
+ add_to_env_config("development", "config.active_support.deprecation = :stderr")
require "rails/all"
super
end
@@ -17,33 +20,36 @@ module ApplicationTests
teardown_app
end
- test 'notes finds notes for certain file_types' do
+ test "notes finds notes for certain file_types" do
app_file "app/views/home/index.html.erb", "<% # TODO: note in erb %>"
app_file "app/assets/javascripts/application.js", "// TODO: note in js"
app_file "app/assets/stylesheets/application.css", "// TODO: note in css"
app_file "app/controllers/application_controller.rb", 1000.times.map { "" }.join("\n") << "# TODO: note in ruby"
app_file "lib/tasks/task.rake", "# TODO: note in rake"
- app_file 'app/views/home/index.html.builder', '# TODO: note in builder'
- app_file 'config/locales/en.yml', '# TODO: note in yml'
- app_file 'config/locales/en.yaml', '# TODO: note in yaml'
+ app_file "app/views/home/index.html.builder", "# TODO: note in builder"
+ app_file "config/locales/en.yml", "# TODO: note in yml"
+ app_file "config/locales/en.yaml", "# TODO: note in yaml"
app_file "app/views/home/index.ruby", "# TODO: note in ruby"
- run_rake_notes do |output, lines|
- assert_match(/note in erb/, output)
- assert_match(/note in js/, output)
- assert_match(/note in css/, output)
- assert_match(/note in rake/, output)
- assert_match(/note in builder/, output)
- assert_match(/note in yml/, output)
- assert_match(/note in yaml/, output)
- assert_match(/note in ruby/, output)
-
- assert_equal 9, lines.size
- assert_equal [4], lines.map(&:size).uniq
+ stderr = capture(:stderr) do
+ run_rake_notes do |output, lines|
+ assert_match(/note in erb/, output)
+ assert_match(/note in js/, output)
+ assert_match(/note in css/, output)
+ assert_match(/note in rake/, output)
+ assert_match(/note in builder/, output)
+ assert_match(/note in yml/, output)
+ assert_match(/note in yaml/, output)
+ assert_match(/note in ruby/, output)
+
+ assert_equal 9, lines.size
+ assert_equal [4], lines.map(&:size).uniq
+ end
end
+ assert_match(/DEPRECATION WARNING: This rake task is deprecated and will be removed in Rails 6.1/, stderr)
end
- test 'notes finds notes in default directories' do
+ test "notes finds notes in default directories" do
app_file "app/controllers/some_controller.rb", "# TODO: note in app directory"
app_file "config/initializers/some_initializer.rb", "# TODO: note in config directory"
app_file "db/some_seeds.rb", "# TODO: note in db directory"
@@ -52,20 +58,23 @@ module ApplicationTests
app_file "some_other_dir/blah.rb", "# TODO: note in some_other directory"
- run_rake_notes do |output, lines|
- assert_match(/note in app directory/, output)
- assert_match(/note in config directory/, output)
- assert_match(/note in db directory/, output)
- assert_match(/note in lib directory/, output)
- assert_match(/note in test directory/, output)
- assert_no_match(/note in some_other directory/, output)
-
- assert_equal 5, lines.size
- assert_equal [4], lines.map(&:size).uniq
+ stderr = capture(:stderr) do
+ run_rake_notes do |output, lines|
+ assert_match(/note in app directory/, output)
+ assert_match(/note in config directory/, output)
+ assert_match(/note in db directory/, output)
+ assert_match(/note in lib directory/, output)
+ assert_match(/note in test directory/, output)
+ assert_no_match(/note in some_other directory/, output)
+
+ assert_equal 5, lines.size
+ assert_equal [4], lines.map(&:size).uniq
+ end
end
+ assert_match(/DEPRECATION WARNING: This rake task is deprecated and will be removed in Rails 6.1/, stderr)
end
- test 'notes finds notes in custom directories' do
+ test "notes finds notes in custom directories" do
app_file "app/controllers/some_controller.rb", "# TODO: note in app directory"
app_file "config/initializers/some_initializer.rb", "# TODO: note in config directory"
app_file "db/some_seeds.rb", "# TODO: note in db directory"
@@ -74,23 +83,28 @@ module ApplicationTests
app_file "some_other_dir/blah.rb", "# TODO: note in some_other directory"
- run_rake_notes "SOURCE_ANNOTATION_DIRECTORIES='some_other_dir' bin/rails notes" do |output, lines|
- assert_match(/note in app directory/, output)
- assert_match(/note in config directory/, output)
- assert_match(/note in db directory/, output)
- assert_match(/note in lib directory/, output)
- assert_match(/note in test directory/, output)
+ stderr = capture(:stderr) do
+ run_rake_notes "SOURCE_ANNOTATION_DIRECTORIES='some_other_dir' bin/rake notes" do |output, lines|
+ assert_match(/note in app directory/, output)
+ assert_match(/note in config directory/, output)
+ assert_match(/note in db directory/, output)
+ assert_match(/note in lib directory/, output)
+ assert_match(/note in test directory/, output)
- assert_match(/note in some_other directory/, output)
+ assert_match(/note in some_other directory/, output)
- assert_equal 6, lines.size
- assert_equal [4], lines.map(&:size).uniq
+ assert_equal 6, lines.size
+ assert_equal [4], lines.map(&:size).uniq
+ end
end
+ assert_match(/DEPRECATION WARNING: This rake task is deprecated and will be removed in Rails 6.1/, stderr)
+ assert_match(/DEPRECATION WARNING: `SOURCE_ANNOTATION_DIRECTORIES` is deprecated and will be removed in Rails 6.1/, stderr)
end
- test 'custom rake task finds specific notes in specific directories' do
+ test "custom rake task finds specific notes in specific directories" do
app_file "app/controllers/some_controller.rb", "# TODO: note in app directory"
- app_file "lib/some_file.rb", "# OPTIMIZE: note in lib directory\n" << "# FIXME: note in lib directory"
+ app_file "lib/some_file.rb", "# OPTIMIZE: note in lib directory\n" \
+ "# FIXME: note in lib directory"
app_file "test/some_test.rb", 1000.times.map { "" }.join("\n") << "# TODO: note in test directory"
app_file "lib/tasks/notes_custom.rake", <<-EOS
@@ -98,7 +112,7 @@ module ApplicationTests
task :notes_custom do
tags = 'TODO|FIXME'
opts = { dirs: %w(lib test), tag: true }
- SourceAnnotationExtractor.enumerate(tags, opts)
+ Rails::SourceAnnotationExtractor.enumerate(tags, opts)
end
EOS
@@ -113,45 +127,48 @@ module ApplicationTests
end
end
- test 'register a new extension' do
+ test "register a new extension" do
add_to_config "config.assets.precompile = []"
add_to_config %q{ config.annotations.register_extensions("scss", "sass") { |annotation| /\/\/\s*(#{annotation}):?\s*(.*)$/ } }
app_file "app/assets/stylesheets/application.css.scss", "// TODO: note in scss"
app_file "app/assets/stylesheets/application.css.sass", "// TODO: note in sass"
- run_rake_notes do |output, lines|
- assert_match(/note in scss/, output)
- assert_match(/note in sass/, output)
- assert_equal 2, lines.size
+ stderr = capture(:stderr) do
+ run_rake_notes do |output, lines|
+ assert_match(/note in scss/, output)
+ assert_match(/note in sass/, output)
+ assert_equal 2, lines.size
+ end
end
+ assert_match(/DEPRECATION WARNING: This rake task is deprecated and will be removed in Rails 6.1/, stderr)
end
- private
+ test "register additional directories" do
+ app_file "spec/spec_helper.rb", "# TODO: note in spec"
+ app_file "spec/models/user_spec.rb", "# TODO: note in model spec"
+ add_to_config ' config.annotations.register_directories("spec") '
- def run_rake_notes(command = 'bin/rails notes')
- boot_rails
- load_tasks
-
- Dir.chdir(app_path) do
- output = `#{command}`
- lines = output.scan(/\[([0-9\s]+)\]\s/).flatten
-
- yield output, lines
+ stderr = capture(:stderr) do
+ run_rake_notes do |output, lines|
+ assert_match(/note in spec/, output)
+ assert_match(/note in model spec/, output)
+ assert_equal 2, lines.size
+ end
end
+ assert_match(/DEPRECATION WARNING: This rake task is deprecated and will be removed in Rails 6.1/, stderr)
end
- def load_tasks
- require 'rake'
- require 'rdoc/task'
- require 'rake/testtask'
+ private
- Rails.application.load_tasks
- end
+ def run_rake_notes(command = "bin/rake notes")
+ Dir.chdir(app_path) do
+ output = `#{command}`
- def boot_rails
- super
- require "#{app_path}/config/environment"
- end
+ lines = output.scan(/\[([0-9\s]+)\]\s/).flatten
+
+ yield output, lines
+ end
+ end
end
end
end
diff --git a/railties/test/application/rake/restart_test.rb b/railties/test/application/rake/restart_test.rb
index 30f662a9be..8614560bf2 100644
--- a/railties/test/application/rake/restart_test.rb
+++ b/railties/test/application/rake/restart_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "isolation/abstract_unit"
module ApplicationTests
@@ -7,40 +9,30 @@ module ApplicationTests
def setup
build_app
- boot_rails
end
def teardown
teardown_app
end
- test 'rake restart touches tmp/restart.txt' do
+ test "rails restart touches tmp/restart.txt" do
Dir.chdir(app_path) do
- `rake restart`
+ rails "restart"
assert File.exist?("tmp/restart.txt")
prev_mtime = File.mtime("tmp/restart.txt")
sleep(1)
- `rake restart`
+ rails "restart"
curr_mtime = File.mtime("tmp/restart.txt")
assert_not_equal prev_mtime, curr_mtime
end
end
- test 'rake restart should work even if tmp folder does not exist' do
- Dir.chdir(app_path) do
- FileUtils.remove_dir('tmp')
- `rake restart`
- assert File.exist?('tmp/restart.txt')
- end
- end
-
- test 'rake restart removes server.pid also' do
+ test "rails restart should work even if tmp folder does not exist" do
Dir.chdir(app_path) do
- FileUtils.mkdir_p("tmp/pids")
- FileUtils.touch("tmp/pids/server.pid")
- `rake restart`
- assert_not File.exist?("tmp/pids/server.pid")
+ FileUtils.remove_dir("tmp")
+ rails "restart"
+ assert File.exist?("tmp/restart.txt")
end
end
end
diff --git a/railties/test/application/rake/routes_test.rb b/railties/test/application/rake/routes_test.rb
new file mode 100644
index 0000000000..9879d1f047
--- /dev/null
+++ b/railties/test/application/rake/routes_test.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+
+module ApplicationTests
+ module RakeTests
+ class RakeRoutesTest < ActiveSupport::TestCase
+ include ActiveSupport::Testing::Isolation
+
+ setup :build_app
+ teardown :teardown_app
+
+ test "`rake routes` outputs routes" do
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ get '/cart', to: 'cart#show'
+ end
+ RUBY
+
+ assert_equal <<~MESSAGE, run_rake_routes
+ 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
+
+ test "`rake routes` outputs a deprecation warning" do
+ add_to_env_config("development", "config.active_support.deprecation = :stderr")
+
+ stderr = capture(:stderr) { run_rake_routes }
+ assert_match(/DEPRECATION WARNING: Using `bin\/rake routes` is deprecated and will be removed in Rails 6.1/, stderr)
+ end
+
+ private
+ def run_rake_routes
+ Dir.chdir(app_path) { `bin/rake routes` }
+ end
+ end
+ end
+end
diff --git a/railties/test/application/rake/tmp_test.rb b/railties/test/application/rake/tmp_test.rb
new file mode 100644
index 0000000000..048fd7adcc
--- /dev/null
+++ b/railties/test/application/rake/tmp_test.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+
+module ApplicationTests
+ module RakeTests
+ class TmpTest < ActiveSupport::TestCase
+ include ActiveSupport::Testing::Isolation
+
+ def setup
+ build_app
+ end
+
+ def teardown
+ teardown_app
+ end
+
+ test "tmp:clear clear cache, socket and screenshot files" do
+ Dir.chdir(app_path) do
+ FileUtils.mkdir_p("tmp/cache")
+ FileUtils.touch("tmp/cache/cache_file")
+
+ FileUtils.mkdir_p("tmp/sockets")
+ FileUtils.touch("tmp/sockets/socket_file")
+
+ FileUtils.mkdir_p("tmp/screenshots")
+ FileUtils.touch("tmp/screenshots/fail.png")
+
+ rails "tmp:clear"
+
+ assert_not File.exist?("tmp/cache/cache_file")
+ assert_not File.exist?("tmp/sockets/socket_file")
+ assert_not File.exist?("tmp/screenshots/fail.png")
+ end
+ end
+
+ test "tmp:clear should work if folder missing" do
+ FileUtils.remove_dir("#{app_path}/tmp")
+ rails "tmp:clear"
+ end
+ end
+ end
+end
diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb
index 1a786a3fd3..fe56e3d076 100644
--- a/railties/test/application/rake_test.rb
+++ b/railties/test/application/rake_test.rb
@@ -1,13 +1,14 @@
+# frozen_string_literal: true
+
require "isolation/abstract_unit"
-require "active_support/core_ext/string/strip"
+require "env_helpers"
module ApplicationTests
class RakeTest < ActiveSupport::TestCase
- include ActiveSupport::Testing::Isolation
+ include ActiveSupport::Testing::Isolation, EnvHelpers
def setup
build_app
- boot_rails
end
def teardown
@@ -25,22 +26,22 @@ module ApplicationTests
end
test "task is protected when previous migration was production" do
- Dir.chdir(app_path) do
- output = `bin/rails generate model product name:string;
- env RAILS_ENV=production bin/rails db:create db:migrate;
- env RAILS_ENV=production bin/rails db:test:prepare test 2>&1`
+ with_rails_env "production" do
+ rails "generate", "model", "product", "name:string"
+ rails "db:create", "db:migrate"
+ output = rails("db:test:prepare", allow_failure: true)
assert_match(/ActiveRecord::ProtectedEnvironmentError/, output)
end
end
def test_not_protected_when_previous_migration_was_not_production
- Dir.chdir(app_path) do
- output = `bin/rails generate model product name:string;
- env RAILS_ENV=test bin/rails db:create db:migrate;
- env RAILS_ENV=test bin/rails db:test:prepare test 2>&1`
+ with_rails_env "test" do
+ rails "generate", "model", "product", "name:string"
+ rails "db:create", "db:migrate"
+ output = rails("db:test:prepare", "test")
- refute_match(/ActiveRecord::ProtectedEnvironmentError/, output)
+ assert_no_match(/ActiveRecord::ProtectedEnvironmentError/, output)
end
end
@@ -55,7 +56,7 @@ module ApplicationTests
Rails.application.initialize!
RUBY
- assert_match("SuperMiddleware", Dir.chdir(app_path){ `bin/rails middleware` })
+ assert_match("SuperMiddleware", rails("middleware"))
end
def test_initializers_are_executed_in_rake_tasks
@@ -70,7 +71,7 @@ module ApplicationTests
end
RUBY
- output = Dir.chdir(app_path){ `bin/rails do_nothing` }
+ output = rails("do_nothing")
assert_match "Doing something...", output
end
@@ -83,7 +84,7 @@ module ApplicationTests
end
RUBY
- app_file 'app/models/hello.rb', <<-RUBY
+ app_file "app/models/hello.rb", <<-RUBY
class Hello
def world
puts 'Hello world'
@@ -91,141 +92,34 @@ module ApplicationTests
end
RUBY
- output = Dir.chdir(app_path) { `bin/rails do_nothing` }
- assert_match 'Hello world', output
+ output = rails("do_nothing")
+ assert_match "Hello world", output
end
def test_should_not_eager_load_model_for_rake
add_to_config <<-RUBY
rake_tasks do
task do_nothing: :environment do
+ puts 'There is nothing'
end
end
RUBY
- add_to_env_config 'production', <<-RUBY
+ add_to_env_config "production", <<-RUBY
config.eager_load = true
RUBY
- app_file 'app/models/hello.rb', <<-RUBY
+ app_file "app/models/hello.rb", <<-RUBY
raise 'should not be pre-required for rake even eager_load=true'
RUBY
- Dir.chdir(app_path) do
- assert system('bin/rails do_nothing RAILS_ENV=production'),
- 'should not be pre-required for rake even eager_load=true'
- end
+ output = rails("do_nothing", "RAILS_ENV=production")
+ assert_match "There is nothing", output
end
def test_code_statistics_sanity
- assert_match "Code LOC: 18 Test LOC: 0 Code to Test Ratio: 1:0.0",
- Dir.chdir(app_path){ `bin/rails stats` }
- end
-
- def test_rails_routes_calls_the_route_inspector
- app_file "config/routes.rb", <<-RUBY
- Rails.application.routes.draw do
- get '/cart', to: 'cart#show'
- end
- RUBY
-
- output = Dir.chdir(app_path){ `bin/rails routes` }
- assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output
- end
-
- def test_rails_routes_with_controller_environment
- app_file "config/routes.rb", <<-RUBY
- Rails.application.routes.draw do
- get '/cart', to: 'cart#show'
- get '/basketball', to: 'basketball#index'
- end
- RUBY
-
- output = Dir.chdir(app_path){ `bin/rails routes CONTROLLER=cart` }
- assert_equal ["Passing `CONTROLLER` to `bin/rails routes` is deprecated and will be removed in Rails 5.1.",
- "Please use `bin/rails routes -c controller_name` instead.",
- "Prefix Verb URI Pattern Controller#Action",
- " cart GET /cart(.:format) cart#show\n"].join("\n"), output
-
- output = Dir.chdir(app_path){ `bin/rails routes -c cart` }
- assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output
- end
-
- def test_rails_routes_with_namespaced_controller_environment
- app_file "config/routes.rb", <<-RUBY
- Rails.application.routes.draw do
- namespace :admin do
- resource :post
- end
- end
- RUBY
- expected_output = [" Prefix Verb URI Pattern Controller#Action",
- " admin_post POST /admin/post(.:format) admin/posts#create",
- " new_admin_post GET /admin/post/new(.:format) admin/posts#new",
- "edit_admin_post GET /admin/post/edit(.:format) admin/posts#edit",
- " 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\n"].join("\n")
-
- output = Dir.chdir(app_path){ `bin/rails routes -c Admin::PostController` }
- assert_equal expected_output, output
-
- output = Dir.chdir(app_path){ `bin/rails routes -c PostController` }
- assert_equal expected_output, output
- end
-
- def test_rails_routes_with_global_search_key
- app_file "config/routes.rb", <<-RUBY
- Rails.application.routes.draw do
- get '/cart', to: 'cart#show'
- post '/cart', to: 'cart#create'
- get '/basketballs', to: 'basketball#index'
- end
- RUBY
-
- output = Dir.chdir(app_path){ `bin/rails routes -g show` }
- assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output
-
- output = Dir.chdir(app_path){ `bin/rails routes -g POST` }
- assert_equal "Prefix Verb URI Pattern Controller#Action\n POST /cart(.:format) cart#create\n", output
-
- output = Dir.chdir(app_path){ `bin/rails routes -g basketballs` }
- assert_equal " Prefix Verb URI Pattern Controller#Action\n" \
- "basketballs GET /basketballs(.:format) basketball#index\n", output
- end
-
- def test_rails_routes_with_controller_search_key
- app_file "config/routes.rb", <<-RUBY
- Rails.application.routes.draw do
- get '/cart', to: 'cart#show'
- get '/basketball', to: 'basketball#index'
- end
- RUBY
-
- output = Dir.chdir(app_path){ `bin/rails routes -c cart` }
- assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output
-
- output = Dir.chdir(app_path){ `bin/rails routes -c Cart` }
- assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output
-
- output = Dir.chdir(app_path){ `bin/rails routes -c CartController` }
- assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output
- end
-
- def test_rails_routes_displays_message_when_no_routes_are_defined
- app_file "config/routes.rb", <<-RUBY
- Rails.application.routes.draw do
- end
- RUBY
-
- assert_equal <<-MESSAGE.strip_heredoc, Dir.chdir(app_path){ `bin/rails routes` }
- You don't have any routes defined!
-
- Please add some routes in config/routes.rb.
-
- For more information about routes, see the Rails guide: http://guides.rubyonrails.org/routing.html.
- MESSAGE
+ assert_match "Code LOC: 32 Test LOC: 0 Code to Test Ratio: 1:0.0",
+ rails("stats")
end
def test_logger_is_flushed_when_exiting_production_rake_tasks
@@ -237,46 +131,42 @@ module ApplicationTests
end
RUBY
- output = Dir.chdir(app_path){ `bin/rails log_something RAILS_ENV=production && cat log/production.log` }
- assert_match "Sample log message", output
+ rails "log_something", "RAILS_ENV=production"
+ assert_match "Sample log message", File.read("#{app_path}/log/production.log")
end
def test_loading_specific_fixtures
- Dir.chdir(app_path) do
- `bin/rails generate model user username:string password:string;
- bin/rails generate model product name:string;
- bin/rails db:migrate`
- end
+ rails "generate", "model", "user", "username:string", "password:string"
+ rails "generate", "model", "product", "name:string"
+ rails "db:migrate"
require "#{rails_root}/config/environment"
# loading a specific fixture
- errormsg = Dir.chdir(app_path) { `bin/rails db:fixtures:load FIXTURES=products` }
- assert $?.success?, errormsg
+ 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
- Dir.chdir(app_path) do
- `bin/rails db:migrate`
- end
+ rails "db:migrate"
app_file "test/fixtures/products.csv", ""
require "#{rails_root}/config/environment"
- errormsg = Dir.chdir(app_path) { `bin/rails db:fixtures:load` }
- assert $?.success?, errormsg
+ rails "db:fixtures:load"
end
def test_scaffold_tests_pass_by_default
- output = Dir.chdir(app_path) do
- `bin/rails generate scaffold user username:string password:string;
- RAILS_ENV=test bin/rails db:migrate test`
+ rails "generate", "scaffold", "user", "username:string", "password:string"
+ with_rails_env("test") do
+ rails("db:migrate")
+ rails("webpacker:compile")
end
+ output = rails("test")
- assert_match(/7 runs, 12 assertions, 0 failures, 0 errors/, output)
+ assert_match(/7 runs, 9 assertions, 0 failures, 0 errors/, output)
assert_no_match(/Errors running/, output)
end
@@ -290,92 +180,71 @@ module ApplicationTests
end
RUBY
- output = Dir.chdir(app_path) do
- `bin/rails generate scaffold user username:string password:string;
- RAILS_ENV=test bin/rails db:migrate test`
- end
+ rails "generate", "scaffold", "user", "username:string", "password:string"
+ with_rails_env("test") { rails("db:migrate") }
+ output = rails("test")
assert_match(/5 runs, 7 assertions, 0 failures, 0 errors/, output)
assert_no_match(/Errors running/, output)
end
def test_scaffold_with_references_columns_tests_pass_by_default
- output = Dir.chdir(app_path) do
- `bin/rails generate model Product;
- bin/rails generate model Cart;
- bin/rails generate scaffold LineItems product:references cart:belongs_to;
- RAILS_ENV=test bin/rails db:migrate test`
+ rails "generate", "model", "Product"
+ rails "generate", "model", "Cart"
+ rails "generate", "scaffold", "LineItems", "product:references", "cart:belongs_to"
+ with_rails_env("test") do
+ rails("db:migrate")
+ rails("webpacker:compile")
end
+ output = rails("test")
- assert_match(/7 runs, 12 assertions, 0 failures, 0 errors/, output)
+ assert_match(/7 runs, 9 assertions, 0 failures, 0 errors/, output)
assert_no_match(/Errors running/, output)
end
- def test_db_test_clone_when_using_sql_format
- add_to_config "config.active_record.schema_format = :sql"
- output = Dir.chdir(app_path) do
- `bin/rails generate scaffold user username:string;
- bin/rails db:migrate;
- bin/rails db:test:clone 2>&1 --trace`
- end
- assert_match(/Execute db:test:clone_structure/, output)
- end
-
def test_db_test_prepare_when_using_sql_format
add_to_config "config.active_record.schema_format = :sql"
- output = Dir.chdir(app_path) do
- `bin/rails generate scaffold user username:string;
- bin/rails db:migrate;
- bin/rails db:test:prepare 2>&1 --trace`
- end
+ rails "generate", "scaffold", "user", "username:string"
+ rails "db:migrate"
+ output = rails("db:test:prepare", "--trace")
assert_match(/Execute db:test:load_structure/, output)
end
def test_rake_dump_structure_should_respect_db_structure_env_variable
- Dir.chdir(app_path) do
- # ensure we have a schema_migrations table to dump
- `bin/rails db:migrate db:structure:dump SCHEMA=db/my_structure.sql`
- end
- assert File.exist?(File.join(app_path, 'db', 'my_structure.sql'))
+ # ensure we have a schema_migrations table to dump
+ rails "db:migrate", "db:structure:dump", "SCHEMA=db/my_structure.sql"
+ assert File.exist?(File.join(app_path, "db", "my_structure.sql"))
end
def test_rake_dump_structure_should_be_called_twice_when_migrate_redo
add_to_config "config.active_record.schema_format = :sql"
- output = Dir.chdir(app_path) do
- `bin/rails g model post title:string;
- bin/rails db:migrate:redo 2>&1 --trace;`
- end
+ rails "g", "model", "post", "title:string"
+ output = rails("db:migrate:redo", "--trace")
# expect only Invoke db:structure:dump (first_time)
assert_no_match(/^\*\* Invoke db:structure:dump\s+$/, output)
end
def test_rake_dump_schema_cache
- Dir.chdir(app_path) do
- `bin/rails generate model post title:string;
- bin/rails generate model product name:string;
- bin/rails db:migrate db:schema:cache:dump`
- end
- assert File.exist?(File.join(app_path, 'db', 'schema_cache.dump'))
+ rails "generate", "model", "post", "title:string"
+ rails "generate", "model", "product", "name:string"
+ rails "db:migrate", "db:schema:cache:dump"
+ assert File.exist?(File.join(app_path, "db", "schema_cache.yml"))
end
def test_rake_clear_schema_cache
- Dir.chdir(app_path) do
- `bin/rails db:schema:cache:dump db:schema:cache:clear`
- end
- assert !File.exist?(File.join(app_path, 'db', 'schema_cache.dump'))
+ rails "db:schema:cache:dump", "db:schema:cache:clear"
+ assert_not File.exist?(File.join(app_path, "db", "schema_cache.yml"))
end
def test_copy_templates
- Dir.chdir(app_path) do
- `bin/rails app:templates:copy`
- %w(controller mailer scaffold).each do |dir|
- assert File.exist?(File.join(app_path, 'lib', 'templates', 'erb', dir))
- end
- %w(controller helper scaffold_controller assets).each do |dir|
- assert File.exist?(File.join(app_path, 'lib', 'templates', 'rails', dir))
- end
+ rails "app:templates:copy"
+ %w(controller mailer scaffold).each do |dir|
+ assert File.exist?(File.join(app_path, "lib", "templates", "erb", dir))
+ end
+ %w(controller helper scaffold_controller assets).each do |dir|
+ assert File.exist?(File.join(app_path, "lib", "templates", "rails", dir))
end
end
@@ -383,18 +252,8 @@ module ApplicationTests
app_file "config/initializers/dummy.rb", "puts 'Hello, World!'"
app_file "template.rb", ""
- output = Dir.chdir(app_path) do
- `bin/rails app:template LOCATION=template.rb`
- end
-
+ output = rails("app:template", "LOCATION=template.rb")
assert_match(/Hello, World!/, output)
end
-
- def test_tmp_clear_should_work_if_folder_missing
- FileUtils.remove_dir("#{app_path}/tmp")
- errormsg = Dir.chdir(app_path) { `bin/rails tmp:clear` }
- assert_predicate $?, :success?
- assert_empty errormsg
- end
end
end
diff --git a/railties/test/application/rendering_test.rb b/railties/test/application/rendering_test.rb
index b01febd768..ab1591f388 100644
--- a/railties/test/application/rendering_test.rb
+++ b/railties/test/application/rendering_test.rb
@@ -1,14 +1,15 @@
-require 'isolation/abstract_unit'
-require 'rack/test'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "rack/test"
module ApplicationTests
- class RoutingTest < ActiveSupport::TestCase
+ class RenderingTest < ActiveSupport::TestCase
include ActiveSupport::Testing::Isolation
include Rack::Test::Methods
def setup
build_app
- boot_rails
end
def teardown
@@ -16,13 +17,13 @@ module ApplicationTests
end
test "Unknown format falls back to HTML template" do
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get 'pages/:id', to: 'pages#show'
end
RUBY
- app_file 'app/controllers/pages_controller.rb', <<-RUBY
+ app_file "app/controllers/pages_controller.rb", <<-RUBY
class PagesController < ApplicationController
layout false
@@ -31,14 +32,14 @@ module ApplicationTests
end
RUBY
- app_file 'app/views/pages/show.html.erb', <<-RUBY
+ app_file "app/views/pages/show.html.erb", <<-RUBY
<%= params[:id] %>
RUBY
- get '/pages/foo'
+ get "/pages/foo"
assert_equal 200, last_response.status
- get '/pages/foo.bar'
+ get "/pages/foo.bar"
assert_equal 200, last_response.status
end
end
diff --git a/railties/test/application/routing_test.rb b/railties/test/application/routing_test.rb
index e51f32aaed..bec038fb51 100644
--- a/railties/test/application/routing_test.rb
+++ b/railties/test/application/routing_test.rb
@@ -1,5 +1,7 @@
-require 'isolation/abstract_unit'
-require 'rack/test'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "rack/test"
module ApplicationTests
class RoutingTest < ActiveSupport::TestCase
@@ -8,7 +10,6 @@ module ApplicationTests
def setup
build_app
- boot_rails
end
def teardown
@@ -39,27 +40,46 @@ module ApplicationTests
assert_equal 200, last_response.status
end
+ test "/rails/info routes are accessible with globbing route present" do
+ app("development")
+
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ get '*foo', to: 'foo#index'
+ end
+ RUBY
+
+ get "/rails/info"
+ assert_equal 302, last_response.status
+
+ get "rails/info/routes"
+ assert_equal 200, last_response.status
+
+ get "rails/info/properties"
+ assert_equal 200, last_response.status
+ end
+
test "root takes precedence over internal welcome controller" do
app("development")
- assert_welcome get('/')
+ assert_welcome get("/")
controller :foo, <<-RUBY
class FooController < ApplicationController
def index
- render text: "foo"
+ render plain: "foo"
end
end
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
root to: "foo#index"
end
RUBY
- get '/'
- assert_equal 'foo', last_response.body
+ get "/"
+ assert_equal "foo", last_response.body
end
test "rails/welcome in production" do
@@ -89,8 +109,8 @@ module ApplicationTests
test "simple controller" do
simple_controller
- get '/foo'
- assert_equal 'foo', last_response.body
+ get "/foo"
+ assert_equal "foo", last_response.body
end
test "simple controller with helper" do
@@ -102,7 +122,7 @@ module ApplicationTests
end
RUBY
- app_file 'app/helpers/bar_helper.rb', <<-RUBY
+ app_file "app/helpers/bar_helper.rb", <<-RUBY
module BarHelper
def foo_or_bar?
"bar"
@@ -110,18 +130,18 @@ module ApplicationTests
end
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get ':controller(/:action)'
end
RUBY
- get '/foo'
- assert_equal 'bar', last_response.body
+ get "/foo"
+ assert_equal "bar", last_response.body
end
test "mount rack app" do
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
mount lambda { |env| [200, {}, [env["PATH_INFO"]]] }, at: "/blog"
# The line below is required because mount sometimes
@@ -130,35 +150,35 @@ module ApplicationTests
end
RUBY
- get '/blog/archives'
- assert_equal '/archives', last_response.body
+ get "/blog/archives"
+ assert_equal "/archives", last_response.body
end
test "mount named rack app" do
controller :foo, <<-RUBY
class FooController < ApplicationController
def index
- render text: my_blog_path
+ render plain: my_blog_path
end
end
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
mount lambda { |env| [200, {}, [env["PATH_INFO"]]] }, at: "/blog", as: "my_blog"
get '/foo' => 'foo#index'
end
RUBY
- get '/foo'
- assert_equal '/blog', last_response.body
+ get "/foo"
+ assert_equal "/blog", last_response.body
end
test "multiple controllers" do
controller :foo, <<-RUBY
class FooController < ApplicationController
def index
- render text: "foo"
+ render plain: "foo"
end
end
RUBY
@@ -166,59 +186,59 @@ module ApplicationTests
controller :bar, <<-RUBY
class BarController < ActionController::Base
def index
- render text: "bar"
+ render plain: "bar"
end
end
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get ':controller(/:action)'
end
RUBY
- get '/foo'
- assert_equal 'foo', last_response.body
+ get "/foo"
+ assert_equal "foo", last_response.body
- get '/bar'
- assert_equal 'bar', last_response.body
+ get "/bar"
+ assert_equal "bar", last_response.body
end
test "nested controller" do
- controller 'foo', <<-RUBY
+ controller "foo", <<-RUBY
class FooController < ApplicationController
def index
- render text: "foo"
+ render plain: "foo"
end
end
RUBY
- controller 'admin/foo', <<-RUBY
+ controller "admin/foo", <<-RUBY
module Admin
class FooController < ApplicationController
def index
- render text: "admin::foo"
+ render plain: "admin::foo"
end
end
end
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get 'admin/foo', to: 'admin/foo#index'
get 'foo', to: 'foo#index'
end
RUBY
- get '/foo'
- assert_equal 'foo', last_response.body
+ get "/foo"
+ assert_equal "foo", last_response.body
- get '/admin/foo'
- assert_equal 'admin::foo', last_response.body
+ get "/admin/foo"
+ assert_equal "admin::foo", last_response.body
end
test "routes appending blocks" do
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get ':controller/:action'
end
@@ -230,60 +250,108 @@ module ApplicationTests
end
R
- app 'development'
+ app "development"
- get '/win'
- assert_equal 'WIN', last_response.body
+ get "/win"
+ assert_equal "WIN", last_response.body
- app_file 'config/routes.rb', <<-R
+ app_file "config/routes.rb", <<-R
Rails.application.routes.draw do
get 'lol' => 'hello#index'
end
R
- get '/win'
- assert_equal 'WIN', last_response.body
+ get "/win"
+ assert_equal "WIN", last_response.body
end
- {"development" => "baz", "production" => "bar"}.each do |mode, expected|
+ {
+ "development" => ["baz", "http://www.apple.com", "/dashboard"],
+ "production" => ["bar", "http://www.microsoft.com", "/profile"]
+ }.each do |mode, (expected_action, expected_url, expected_mapping)|
test "reloads routes when configuration is changed in #{mode}" do
controller :foo, <<-RUBY
class FooController < ApplicationController
def bar
- render text: "bar"
+ render plain: "bar"
end
def baz
- render text: "baz"
+ render plain: "baz"
+ end
+
+ def custom
+ render plain: custom_url
+ end
+
+ def mapping
+ render plain: url_for(User.new)
end
end
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "app/models/user.rb", <<-RUBY
+ class User
+ extend ActiveModel::Naming
+ include ActiveModel::Conversion
+
+ def self.model_name
+ @_model_name ||= ActiveModel::Name.new(self.class, nil, "User")
+ end
+
+ def persisted?
+ false
+ end
+ end
+ RUBY
+
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get 'foo', to: 'foo#bar'
+ get 'custom', to: 'foo#custom'
+ get 'mapping', to: 'foo#mapping'
+
+ direct(:custom) { "http://www.microsoft.com" }
+ resolve("User") { "/profile" }
end
RUBY
app(mode)
- get '/foo'
- assert_equal 'bar', last_response.body
+ get "/foo"
+ assert_equal "bar", last_response.body
+
+ get "/custom"
+ assert_equal "http://www.microsoft.com", last_response.body
+
+ get "/mapping"
+ assert_equal "/profile", last_response.body
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get 'foo', to: 'foo#baz'
+ get 'custom', to: 'foo#custom'
+ get 'mapping', to: 'foo#mapping'
+
+ direct(:custom) { "http://www.apple.com" }
+ resolve("User") { "/dashboard" }
end
RUBY
sleep 0.1
- get '/foo'
- assert_equal expected, last_response.body
+ get "/foo"
+ assert_equal expected_action, last_response.body
+
+ get "/custom"
+ assert_equal expected_url, last_response.body
+
+ get "/mapping"
+ assert_equal expected_mapping, last_response.body
end
end
- test 'routes are loaded just after initialization' do
+ test "routes are loaded just after initialization" do
require "#{app_path}/config/application"
# Create the rack app just inside after initialize callback
@@ -291,17 +359,17 @@ module ApplicationTests
::InitializeRackApp = lambda { |env| [200, {}, ["InitializeRackApp"]] }
end
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get 'foo', to: ::InitializeRackApp
end
RUBY
- get '/foo'
+ get "/foo"
assert_equal "InitializeRackApp", last_response.body
end
- test 'reload_routes! is part of Rails.application API' do
+ test "reload_routes! is part of Rails.application API" do
app("development")
assert_nothing_raised do
Rails.application.reload_routes!
@@ -309,36 +377,44 @@ module ApplicationTests
end
def test_root_path
- app('development')
+ app("development")
controller :foo, <<-RUBY
class FooController < ApplicationController
def index
- render :text => "foo"
+ render plain: "foo"
end
end
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get 'foo', :to => 'foo#index'
root :to => 'foo#index'
end
RUBY
- remove_file 'public/index.html'
+ remove_file "public/index.html"
- get '/'
- assert_equal 'foo', last_response.body
+ get "/"
+ assert_equal "foo", last_response.body
end
- test 'routes are added and removed when reloading' do
- app('development')
+ test "routes are added and removed when reloading" do
+ app("development")
controller :foo, <<-RUBY
class FooController < ApplicationController
def index
- render text: "foo"
+ render plain: "foo"
+ end
+
+ def custom
+ render plain: custom_url
+ end
+
+ def mapping
+ render plain: url_for(User.new)
end
end
RUBY
@@ -346,45 +422,74 @@ module ApplicationTests
controller :bar, <<-RUBY
class BarController < ApplicationController
def index
- render text: "bar"
+ render plain: "bar"
+ end
+ end
+ RUBY
+
+ app_file "app/models/user.rb", <<-RUBY
+ class User
+ extend ActiveModel::Naming
+ include ActiveModel::Conversion
+
+ def self.model_name
+ @_model_name ||= ActiveModel::Name.new(self.class, nil, "User")
+ end
+
+ def persisted?
+ false
end
end
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get 'foo', to: 'foo#index'
end
RUBY
- get '/foo'
- assert_equal 'foo', last_response.body
- assert_equal '/foo', Rails.application.routes.url_helpers.foo_path
+ get "/foo"
+ assert_equal "foo", last_response.body
+ assert_equal "/foo", Rails.application.routes.url_helpers.foo_path
- get '/bar'
+ get "/bar"
assert_equal 404, last_response.status
assert_raises NoMethodError do
- assert_equal '/bar', Rails.application.routes.url_helpers.bar_path
+ assert_equal "/bar", Rails.application.routes.url_helpers.bar_path
end
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get 'foo', to: 'foo#index'
get 'bar', to: 'bar#index'
+
+ get 'custom', to: 'foo#custom'
+ direct(:custom) { 'http://www.apple.com' }
+
+ get 'mapping', to: 'foo#mapping'
+ resolve('User') { '/profile' }
end
RUBY
Rails.application.reload_routes!
- get '/foo'
- assert_equal 'foo', last_response.body
- assert_equal '/foo', Rails.application.routes.url_helpers.foo_path
+ get "/foo"
+ assert_equal "foo", last_response.body
+ assert_equal "/foo", Rails.application.routes.url_helpers.foo_path
+
+ get "/bar"
+ assert_equal "bar", last_response.body
+ assert_equal "/bar", Rails.application.routes.url_helpers.bar_path
+
+ get "/custom"
+ assert_equal "http://www.apple.com", last_response.body
+ assert_equal "http://www.apple.com", Rails.application.routes.url_helpers.custom_url
- get '/bar'
- assert_equal 'bar', last_response.body
- assert_equal '/bar', Rails.application.routes.url_helpers.bar_path
+ get "/mapping"
+ assert_equal "/profile", last_response.body
+ assert_equal "/profile", Rails.application.routes.url_helpers.polymorphic_path(User.new)
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get 'foo', to: 'foo#index'
end
@@ -392,24 +497,36 @@ module ApplicationTests
Rails.application.reload_routes!
- get '/foo'
- assert_equal 'foo', last_response.body
- assert_equal '/foo', Rails.application.routes.url_helpers.foo_path
+ get "/foo"
+ assert_equal "foo", last_response.body
+ assert_equal "/foo", Rails.application.routes.url_helpers.foo_path
- get '/bar'
+ get "/bar"
assert_equal 404, last_response.status
assert_raises NoMethodError do
- assert_equal '/bar', Rails.application.routes.url_helpers.bar_path
+ assert_equal "/bar", Rails.application.routes.url_helpers.bar_path
+ end
+
+ get "/custom"
+ assert_equal 404, last_response.status
+ assert_raises NoMethodError do
+ assert_equal "http://www.apple.com", Rails.application.routes.url_helpers.custom_url
+ end
+
+ get "/mapping"
+ assert_equal 404, last_response.status
+ assert_raises NoMethodError do
+ assert_equal "/profile", Rails.application.routes.url_helpers.polymorphic_path(User.new)
end
end
- test 'named routes are cleared when reloading' do
- app('development')
+ test "named routes are cleared when reloading" do
+ app("development")
controller :foo, <<-RUBY
class FooController < ApplicationController
def index
- render text: "foo"
+ render plain: "foo"
end
end
RUBY
@@ -417,63 +534,149 @@ module ApplicationTests
controller :bar, <<-RUBY
class BarController < ApplicationController
def index
- render text: "bar"
+ render plain: "bar"
+ end
+ end
+ RUBY
+
+ app_file "app/models/user.rb", <<-RUBY
+ class User
+ extend ActiveModel::Naming
+ include ActiveModel::Conversion
+
+ def self.model_name
+ @_model_name ||= ActiveModel::Name.new(self.class, nil, "User")
+ end
+
+ def persisted?
+ false
end
end
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get ':locale/foo', to: 'foo#index', as: 'foo'
+ get 'users', to: 'foo#users', as: 'users'
+ direct(:microsoft) { 'http://www.microsoft.com' }
+ resolve('User') { '/profile' }
end
RUBY
- get '/en/foo'
- assert_equal 'foo', last_response.body
- assert_equal '/en/foo', Rails.application.routes.url_helpers.foo_path(:locale => 'en')
+ get "/en/foo"
+ assert_equal "foo", last_response.body
+ assert_equal "/en/foo", Rails.application.routes.url_helpers.foo_path(locale: "en")
+ assert_equal "http://www.microsoft.com", Rails.application.routes.url_helpers.microsoft_url
+ assert_equal "/profile", Rails.application.routes.url_helpers.polymorphic_path(User.new)
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get ':locale/bar', to: 'bar#index', as: 'foo'
+ get 'users', to: 'foo#users', as: 'users'
+ direct(:apple) { 'http://www.apple.com' }
end
RUBY
Rails.application.reload_routes!
- get '/en/foo'
+ get "/en/foo"
assert_equal 404, last_response.status
- get '/en/bar'
- assert_equal 'bar', last_response.body
- assert_equal '/en/bar', Rails.application.routes.url_helpers.foo_path(:locale => 'en')
+ get "/en/bar"
+ assert_equal "bar", last_response.body
+ assert_equal "/en/bar", Rails.application.routes.url_helpers.foo_path(locale: "en")
+ assert_equal "http://www.apple.com", Rails.application.routes.url_helpers.apple_url
+ assert_equal "/users", Rails.application.routes.url_helpers.polymorphic_path(User.new)
+
+ assert_raises NoMethodError do
+ assert_equal "http://www.microsoft.com", Rails.application.routes.url_helpers.microsoft_url
+ end
end
- test 'resource routing with irregular inflection' do
- app_file 'config/initializers/inflection.rb', <<-RUBY
+ test "resource routing with irregular inflection" do
+ app_file "config/initializers/inflection.rb", <<-RUBY
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'yazi', 'yazilar'
end
RUBY
- app_file 'config/routes.rb', <<-RUBY
+ app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
resources :yazilar
end
RUBY
- controller 'yazilar', <<-RUBY
+ controller "yazilar", <<-RUBY
class YazilarController < ApplicationController
def index
- render text: 'yazilar#index'
+ render plain: 'yazilar#index'
end
end
RUBY
- get '/yazilars'
+ get "/yazilars"
assert_equal 404, last_response.status
- get '/yazilar'
+ get "/yazilar"
assert_equal 200, last_response.status
end
+
+ test "reloading routes removes methods and doesn't undefine them" do
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ get '/url', to: 'url#index'
+ end
+ RUBY
+
+ app_file "app/models/url_helpers.rb", <<-RUBY
+ module UrlHelpers
+ def foo_path
+ "/foo"
+ end
+ end
+ RUBY
+
+ app_file "app/models/context.rb", <<-RUBY
+ class Context
+ include UrlHelpers
+ include Rails.application.routes.url_helpers
+ end
+ RUBY
+
+ controller "url", <<-RUBY
+ class UrlController < ApplicationController
+ def index
+ context = Context.new
+ render plain: context.foo_path
+ end
+ end
+ RUBY
+
+ get "/url"
+ assert_equal "/foo", last_response.body
+
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ get '/url', to: 'url#index'
+ get '/bar', to: 'foo#index', as: 'foo'
+ end
+ RUBY
+
+ Rails.application.reload_routes!
+
+ get "/url"
+ assert_equal "/bar", last_response.body
+
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ get '/url', to: 'url#index'
+ end
+ RUBY
+
+ Rails.application.reload_routes!
+
+ get "/url"
+ assert_equal "/foo", last_response.body
+ end
end
end
diff --git a/railties/test/application/runner_test.rb b/railties/test/application/runner_test.rb
index 9f15ce5e85..dfb9540093 100644
--- a/railties/test/application/runner_test.rb
+++ b/railties/test/application/runner_test.rb
@@ -1,5 +1,7 @@
-require 'isolation/abstract_unit'
-require 'env_helpers'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "env_helpers"
module ApplicationTests
class RunnerTest < ActiveSupport::TestCase
@@ -8,7 +10,6 @@ module ApplicationTests
def setup
build_app
- boot_rails
# Lets create a model so we have something to play with
app_file "app/models/user.rb", <<-MODEL
@@ -25,15 +26,20 @@ module ApplicationTests
end
def test_should_include_runner_in_shebang_line_in_help_without_option
- assert_match "/rails runner", Dir.chdir(app_path) { `bin/rails runner` }
+ assert_match "/rails runner", rails("runner", allow_failure: true)
end
def test_should_include_runner_in_shebang_line_in_help
- assert_match "/rails runner", Dir.chdir(app_path) { `bin/rails runner --help` }
+ assert_match "/rails runner", rails("runner", "--help")
end
def test_should_run_ruby_statement
- assert_match "42", Dir.chdir(app_path) { `bin/rails runner "puts User.count"` }
+ assert_match "42", rails("runner", "puts User.count")
+ end
+
+ def test_should_set_argv_when_running_code
+ output = rails("runner", "puts ARGV.join(',')", "--foo", "a1", "-b", "a2", "a3", "--moo")
+ assert_equal "--foo,a1,-b,a2,a3,--moo", output.chomp
end
def test_should_run_file
@@ -41,7 +47,16 @@ module ApplicationTests
puts User.count
SCRIPT
- assert_match "42", Dir.chdir(app_path) { `bin/rails runner "bin/count_users.rb"` }
+ assert_match "42", rails("runner", "bin/count_users.rb")
+ end
+
+ def test_no_minitest_loaded_in_production_mode
+ app_file "bin/print_features.rb", <<-SCRIPT
+ p $LOADED_FEATURES.grep(/minitest/)
+ SCRIPT
+ assert_match "[]", Dir.chdir(app_path) {
+ `RAILS_ENV=production bin/rails runner "bin/print_features.rb"`
+ }
end
def test_should_set_dollar_0_to_file
@@ -49,7 +64,7 @@ module ApplicationTests
puts $0
SCRIPT
- assert_match "bin/dollar0.rb", Dir.chdir(app_path) { `bin/rails runner "bin/dollar0.rb"` }
+ assert_match "bin/dollar0.rb", rails("runner", "bin/dollar0.rb")
end
def test_should_set_dollar_program_name_to_file
@@ -57,7 +72,23 @@ module ApplicationTests
puts $PROGRAM_NAME
SCRIPT
- assert_match "bin/program_name.rb", Dir.chdir(app_path) { `bin/rails runner "bin/program_name.rb"` }
+ assert_match "bin/program_name.rb", rails("runner", "bin/program_name.rb")
+ end
+
+ def test_passes_extra_args_to_file
+ app_file "bin/program_name.rb", <<-SCRIPT
+ p ARGV
+ SCRIPT
+
+ assert_match %w( a b ).to_s, rails("runner", "bin/program_name.rb", "a", "b")
+ end
+
+ def test_should_run_stdin
+ app_file "bin/count_users.rb", <<-SCRIPT
+ puts User.count
+ SCRIPT
+
+ assert_match "42", Dir.chdir(app_path) { `cat bin/count_users.rb | bin/rails runner -` }
end
def test_with_hook
@@ -67,33 +98,55 @@ module ApplicationTests
end
RUBY
- assert_match "true", Dir.chdir(app_path) { `bin/rails runner "puts Rails.application.config.ran"` }
+ assert_match "true", rails("runner", "puts Rails.application.config.ran")
end
def test_default_environment
- assert_match "development", Dir.chdir(app_path) { `bin/rails runner "puts Rails.env"` }
+ assert_match "development", rails("runner", "puts Rails.env")
+ end
+
+ def test_environment_option
+ assert_match "production", rails("runner", "-e", "production", "puts Rails.env")
+ end
+
+ def test_environment_option_is_properly_expanded
+ assert_match "production", rails("runner", "-e", "prod", "puts Rails.env")
end
def test_runner_detects_syntax_errors
- Dir.chdir(app_path) { `bin/rails runner "puts 'hello world" 2>&1` }
- refute $?.success?
+ output = rails("runner", "puts 'hello world", allow_failure: true)
+ assert_not_predicate $?, :success?
+ assert_match "unterminated string meets end of file", output
end
def test_runner_detects_bad_script_name
- Dir.chdir(app_path) { `bin/rails runner "iuiqwiourowe" 2>&1` }
- refute $?.success?
+ output = rails("runner", "iuiqwiourowe", allow_failure: true)
+ assert_not_predicate $?, :success?
+ assert_match "undefined local variable or method `iuiqwiourowe' for", output
end
def test_environment_with_rails_env
with_rails_env "production" do
- assert_match "production", Dir.chdir(app_path) { `bin/rails runner "puts Rails.env"` }
+ assert_match "production", rails("runner", "puts Rails.env")
end
end
def test_environment_with_rack_env
with_rack_env "production" do
- assert_match "production", Dir.chdir(app_path) { `bin/rails runner "puts Rails.env"` }
+ assert_match "production", rails("runner", "puts Rails.env")
+ end
+ end
+
+ def test_can_call_same_name_class_as_defined_in_thor
+ app_file "app/models/task.rb", <<-MODEL
+ class Task
+ def self.count
+ 42
+ end
end
+ MODEL
+
+ assert_match "42", rails("runner", "puts Task.count")
end
end
end
diff --git a/railties/test/application/server_test.rb b/railties/test/application/server_test.rb
new file mode 100644
index 0000000000..5fe1b4e6e7
--- /dev/null
+++ b/railties/test/application/server_test.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "console_helpers"
+require "rails/command"
+require "rails/commands/server/server_command"
+
+module ApplicationTests
+ class ServerTest < ActiveSupport::TestCase
+ include ActiveSupport::Testing::Isolation
+ include ConsoleHelpers
+
+ def setup
+ build_app
+ end
+
+ def teardown
+ teardown_app
+ end
+
+ test "restart rails server with custom pid file path" do
+ skip "PTY unavailable" unless available_pty?
+
+ File.open("#{app_path}/config/boot.rb", "w") do |f|
+ f.puts "ENV['BUNDLE_GEMFILE'] = '#{Bundler.default_gemfile}'"
+ f.puts "require 'bundler/setup'"
+ end
+
+ primary, replica = PTY.open
+ pid = nil
+
+ Bundler.with_original_env do
+ pid = Process.spawn("bin/rails server -b localhost -P tmp/dummy.pid", chdir: app_path, in: replica, out: replica, err: replica)
+ assert_output("Listening", primary)
+
+ rails("restart")
+
+ assert_output("Restarting", primary)
+ assert_output("tcp://localhost:3000", primary)
+ ensure
+ kill(pid) if pid
+ end
+ end
+
+ private
+ def kill(pid)
+ Process.kill("TERM", pid)
+ Process.wait(pid)
+ rescue Errno::ESRCH
+ end
+ end
+end
diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb
index a1735db5b3..0bdd2b314d 100644
--- a/railties/test/application/test_runner_test.rb
+++ b/railties/test/application/test_runner_test.rb
@@ -1,6 +1,7 @@
-require 'isolation/abstract_unit'
-require 'active_support/core_ext/string/strip'
-require 'env_helpers'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "env_helpers"
module ApplicationTests
class TestRunnerTest < ActiveSupport::TestCase
@@ -15,32 +16,56 @@ module ApplicationTests
teardown_app
end
+ def test_run_via_backwards_compatibility
+ require "minitest/rails_plugin"
+
+ assert_nothing_raised do
+ Minitest.run_via[:ruby] = true
+ end
+
+ assert Minitest.run_via[:ruby]
+ end
+
def test_run_single_file
- create_test_file :models, 'foo'
- create_test_file :models, 'bar'
+ create_test_file :models, "foo"
+ create_test_file :models, "bar"
assert_match "1 runs, 1 assertions, 0 failures", run_test_command("test/models/foo_test.rb")
end
+ def test_run_single_file_with_absolute_path
+ create_test_file :models, "foo"
+ create_test_file :models, "bar"
+ assert_match "1 runs, 1 assertions, 0 failures", run_test_command("#{app_path}/test/models/foo_test.rb")
+ end
+
def test_run_multiple_files
- create_test_file :models, 'foo'
- create_test_file :models, 'bar'
+ create_test_file :models, "foo"
+ create_test_file :models, "bar"
assert_match "2 runs, 2 assertions, 0 failures", run_test_command("test/models/foo_test.rb test/models/bar_test.rb")
end
+ def test_run_multiple_files_with_absolute_paths
+ create_test_file :models, "foo"
+ create_test_file :controllers, "foobar_controller"
+ create_test_file :models, "bar"
+
+ assert_match "2 runs, 2 assertions, 0 failures", run_test_command("#{app_path}/test/models/foo_test.rb #{app_path}/test/controllers/foobar_controller_test.rb")
+ end
+
def test_run_file_with_syntax_error
- app_file 'test/models/error_test.rb', <<-RUBY
+ app_file "test/models/error_test.rb", <<-RUBY
require 'test_helper'
def; end
RUBY
- error = capture(:stderr) { run_test_command('test/models/error_test.rb') }
+ error = capture(:stderr) { run_test_command("test/models/error_test.rb", stderr: true) }
assert_match "syntax error", error
end
def test_run_models
- create_test_file :models, 'foo'
- create_test_file :models, 'bar'
- create_test_file :controllers, 'foobar_controller'
+ create_test_file :models, "foo"
+ create_test_file :models, "bar"
+ create_test_file :controllers, "foobar_controller"
run_test_command("test/models").tap do |output|
assert_match "FooTest", output
assert_match "BarTest", output
@@ -49,9 +74,9 @@ module ApplicationTests
end
def test_run_helpers
- create_test_file :helpers, 'foo_helper'
- create_test_file :helpers, 'bar_helper'
- create_test_file :controllers, 'foobar_controller'
+ create_test_file :helpers, "foo_helper"
+ create_test_file :helpers, "bar_helper"
+ create_test_file :controllers, "foobar_controller"
run_test_command("test/helpers").tap do |output|
assert_match "FooHelperTest", output
assert_match "BarHelperTest", output
@@ -60,12 +85,12 @@ module ApplicationTests
end
def test_run_units
- skip "we no longer have the concept of unit tests. Just different directories..."
- create_test_file :models, 'foo'
- create_test_file :helpers, 'bar_helper'
- create_test_file :unit, 'baz_unit'
- create_test_file :controllers, 'foobar_controller'
- run_test_units_command.tap do |output|
+ create_test_file :models, "foo"
+ create_test_file :helpers, "bar_helper"
+ create_test_file :unit, "baz_unit"
+ create_test_file :controllers, "foobar_controller"
+
+ rails("test:units").tap do |output|
assert_match "FooTest", output
assert_match "BarHelperTest", output
assert_match "BazUnitTest", output
@@ -73,10 +98,21 @@ 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'
- create_test_file :models, 'foo'
+ create_test_file :controllers, "foo_controller"
+ create_test_file :controllers, "bar_controller"
+ create_test_file :models, "foo"
run_test_command("test/controllers").tap do |output|
assert_match "FooControllerTest", output
assert_match "BarControllerTest", output
@@ -85,9 +121,9 @@ module ApplicationTests
end
def test_run_mailers
- create_test_file :mailers, 'foo_mailer'
- create_test_file :mailers, 'bar_mailer'
- create_test_file :models, 'foo'
+ create_test_file :mailers, "foo_mailer"
+ create_test_file :mailers, "bar_mailer"
+ create_test_file :models, "foo"
run_test_command("test/mailers").tap do |output|
assert_match "FooMailerTest", output
assert_match "BarMailerTest", output
@@ -96,9 +132,9 @@ module ApplicationTests
end
def test_run_jobs
- create_test_file :jobs, 'foo_job'
- create_test_file :jobs, 'bar_job'
- create_test_file :models, 'foo'
+ create_test_file :jobs, "foo_job"
+ create_test_file :jobs, "bar_job"
+ create_test_file :models, "foo"
run_test_command("test/jobs").tap do |output|
assert_match "FooJobTest", output
assert_match "BarJobTest", output
@@ -106,13 +142,25 @@ 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
- skip "we no longer have the concept of functional tests. Just different directories..."
- create_test_file :mailers, 'foo_mailer'
- create_test_file :controllers, 'bar_controller'
- create_test_file :functional, 'baz_functional'
- create_test_file :models, 'foo'
- run_test_functionals_command.tap do |output|
+ create_test_file :mailers, "foo_mailer"
+ create_test_file :controllers, "bar_controller"
+ create_test_file :functional, "baz_functional"
+ create_test_file :models, "foo"
+
+ rails("test:functionals").tap do |output|
assert_match "FooMailerTest", output
assert_match "BarControllerTest", output
assert_match "BazFunctionalTest", output
@@ -121,8 +169,8 @@ module ApplicationTests
end
def test_run_integration
- create_test_file :integration, 'foo_integration'
- create_test_file :models, 'foo'
+ create_test_file :integration, "foo_integration"
+ create_test_file :models, "foo"
run_test_command("test/integration").tap do |output|
assert_match "FooIntegration", output
assert_match "1 runs, 1 assertions, 0 failures", output
@@ -130,16 +178,16 @@ 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|
+ 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
def test_run_named_test
- app_file 'test/unit/chu_2_koi_test.rb', <<-RUBY
+ app_file "test/unit/chu_2_koi_test.rb", <<-RUBY
require 'test_helper'
class Chu2KoiTest < ActiveSupport::TestCase
@@ -153,14 +201,14 @@ module ApplicationTests
end
RUBY
- run_test_command('-n test_rikka test/unit/chu_2_koi_test.rb').tap do |output|
+ run_test_command("-n test_rikka test/unit/chu_2_koi_test.rb").tap do |output|
assert_match "Rikka", output
assert_no_match "Sanae", output
end
end
def test_run_matched_test
- app_file 'test/unit/chu_2_koi_test.rb', <<-RUBY
+ app_file "test/unit/chu_2_koi_test.rb", <<-RUBY
require 'test_helper'
class Chu2KoiTest < ActiveSupport::TestCase
@@ -174,7 +222,7 @@ module ApplicationTests
end
RUBY
- run_test_command('-n /rikka/ test/unit/chu_2_koi_test.rb').tap do |output|
+ run_test_command("-n /rikka/ test/unit/chu_2_koi_test.rb").tap do |output|
assert_match "Rikka", output
assert_no_match "Sanae", output
end
@@ -195,14 +243,14 @@ module ApplicationTests
def test_run_with_model
skip "These feel a bit odd. Not sure we should keep supporting them."
create_model_with_fixture
- create_fixture_test 'models', 'user'
+ create_fixture_test "models", "user"
assert_match "3 users", run_task(["test models/user"])
assert_match "3 users", run_task(["test app/models/user.rb"])
end
def test_run_different_environment_using_env_var
skip "no longer possible. Running tests in a different environment should be explicit"
- app_file 'test/unit/env_test.rb', <<-RUBY
+ app_file "test/unit/env_test.rb", <<-RUBY
require 'test_helper'
class EnvTest < ActiveSupport::TestCase
@@ -212,14 +260,14 @@ module ApplicationTests
end
RUBY
- ENV['RAILS_ENV'] = 'development'
- assert_match "development", run_test_command('test/unit/env_test.rb')
+ ENV["RAILS_ENV"] = "development"
+ assert_match "development", run_test_command("test/unit/env_test.rb")
end
def test_run_in_test_environment_by_default
create_env_test
- assert_match "Current Environment: test", run_test_command('test/unit/env_test.rb')
+ assert_match "Current Environment: test", run_test_command("test/unit/env_test.rb")
end
def test_run_different_environment
@@ -231,27 +279,39 @@ module ApplicationTests
def test_generated_scaffold_works_with_rails_test
create_scaffold
- assert_match "0 failures, 0 errors, 0 skips", run_test_command('')
+ assert_match "0 failures, 0 errors, 0 skips", run_test_command("")
end
def test_generated_controller_works_with_rails_test
create_controller
- assert_match "0 failures, 0 errors, 0 skips", run_test_command('')
+ assert_match "0 failures, 0 errors, 0 skips", run_test_command("")
end
def test_run_multiple_folders
- create_test_file :models, 'account'
- create_test_file :controllers, 'accounts_controller'
+ create_test_file :models, "account"
+ create_test_file :controllers, "accounts_controller"
+
+ run_test_command("test/models test/controllers").tap do |output|
+ assert_match "AccountTest", output
+ assert_match "AccountsControllerTest", output
+ assert_match "2 runs, 2 assertions, 0 failures, 0 errors, 0 skips", output
+ end
+ end
+
+ def test_run_multiple_folders_with_absolute_paths
+ create_test_file :models, "account"
+ create_test_file :controllers, "accounts_controller"
+ create_test_file :helpers, "foo_helper"
- run_test_command('test/models test/controllers').tap do |output|
- assert_match 'AccountTest', output
- assert_match 'AccountsControllerTest', output
- assert_match '2 runs, 2 assertions, 0 failures, 0 errors, 0 skips', output
+ run_test_command("#{app_path}/test/models #{app_path}/test/controllers").tap do |output|
+ assert_match "AccountTest", output
+ assert_match "AccountsControllerTest", output
+ assert_match "2 runs, 2 assertions, 0 failures, 0 errors, 0 skips", output
end
end
def test_run_with_ruby_command
- app_file 'test/models/post_test.rb', <<-RUBY
+ app_file "test/models/post_test.rb", <<-RUBY
require 'test_helper'
class PostTest < ActiveSupport::TestCase
@@ -264,15 +324,15 @@ module ApplicationTests
Dir.chdir(app_path) do
`ruby -Itest test/models/post_test.rb`.tap do |output|
- assert_match 'PostTest', output
- assert_no_match 'is already defined in', output
+ assert_match "PostTest", output
+ assert_no_match "is already defined in", output
end
end
end
def test_mix_files_and_line_filters
- create_test_file :models, 'account'
- app_file 'test/models/post_test.rb', <<-RUBY
+ create_test_file :models, "account"
+ app_file "test/models/post_test.rb", <<-RUBY
require 'test_helper'
class PostTest < ActiveSupport::TestCase
@@ -287,15 +347,15 @@ module ApplicationTests
end
RUBY
- run_test_command('test/models/account_test.rb test/models/post_test.rb:4').tap do |output|
- assert_match 'AccountTest', output
- assert_match 'PostTest', output
- assert_match '2 runs, 2 assertions', output
+ run_test_command("test/models/account_test.rb test/models/post_test.rb:4").tap do |output|
+ assert_match "AccountTest", output
+ assert_match "PostTest", output
+ assert_match "2 runs, 2 assertions", output
end
end
def test_more_than_one_line_filter
- app_file 'test/models/post_test.rb', <<-RUBY
+ app_file "test/models/post_test.rb", <<-RUBY
require 'test_helper'
class PostTest < ActiveSupport::TestCase
@@ -309,21 +369,21 @@ module ApplicationTests
assert true
end
- test "test line filter does not run this" do
+ test "line filter does not run this" do
assert true
end
end
RUBY
- run_test_command('test/models/post_test.rb:4:9').tap do |output|
- assert_match 'PostTest:FirstFilter', output
- assert_match 'PostTest:SecondFilter', output
- assert_match '2 runs, 2 assertions', output
+ run_test_command("test/models/post_test.rb:4:9").tap do |output|
+ assert_match "PostTest:FirstFilter", output
+ assert_match "PostTest:SecondFilter", output
+ assert_match "2 runs, 2 assertions", output
end
end
def test_more_than_one_line_filter_with_multiple_files
- app_file 'test/models/account_test.rb', <<-RUBY
+ app_file "test/models/account_test.rb", <<-RUBY
require 'test_helper'
class AccountTest < ActiveSupport::TestCase
@@ -343,7 +403,7 @@ module ApplicationTests
end
RUBY
- app_file 'test/models/post_test.rb', <<-RUBY
+ app_file "test/models/post_test.rb", <<-RUBY
require 'test_helper'
class PostTest < ActiveSupport::TestCase
@@ -363,27 +423,27 @@ module ApplicationTests
end
RUBY
- run_test_command('test/models/account_test.rb:4:9 test/models/post_test.rb:4:9').tap do |output|
- assert_match 'AccountTest:FirstFilter', output
- assert_match 'AccountTest:SecondFilter', output
- assert_match 'PostTest:FirstFilter', output
- assert_match 'PostTest:SecondFilter', output
- assert_match '4 runs, 4 assertions', output
+ run_test_command("test/models/account_test.rb:4:9 test/models/post_test.rb:4:9").tap do |output|
+ assert_match "AccountTest:FirstFilter", output
+ assert_match "AccountTest:SecondFilter", output
+ assert_match "PostTest:FirstFilter", output
+ assert_match "PostTest:SecondFilter", output
+ assert_match "4 runs, 4 assertions", output
end
end
def test_multiple_line_filters
- create_test_file :models, 'account'
- create_test_file :models, 'post'
+ create_test_file :models, "account"
+ create_test_file :models, "post"
- run_test_command('test/models/account_test.rb:4 test/models/post_test.rb:4').tap do |output|
- assert_match 'AccountTest', output
- assert_match 'PostTest', output
+ run_test_command("test/models/account_test.rb:4 test/models/post_test.rb:4").tap do |output|
+ assert_match "AccountTest", output
+ assert_match "PostTest", output
end
end
def test_line_filters_trigger_only_one_runnable
- app_file 'test/models/post_test.rb', <<-RUBY
+ app_file "test/models/post_test.rb", <<-RUBY
require 'test_helper'
class PostTest < ActiveSupport::TestCase
@@ -400,14 +460,14 @@ module ApplicationTests
RUBY
# Pass seed guaranteeing failure.
- run_test_command('test/models/post_test.rb:4 --seed 30410').tap do |output|
- assert_no_match 'ran second runnable', output
- assert_match '1 runs, 1 assertions', output
+ run_test_command("test/models/post_test.rb:4 --seed 30410").tap do |output|
+ assert_no_match "ran second runnable", output
+ assert_match "1 runs, 1 assertions", output
end
end
def test_line_filter_with_minitest_string_filter
- app_file 'test/models/post_test.rb', <<-RUBY
+ app_file "test/models/post_test.rb", <<-RUBY
require 'test_helper'
class PostTest < ActiveSupport::TestCase
@@ -423,120 +483,373 @@ module ApplicationTests
end
RUBY
- run_test_command('test/models/post_test.rb:4 -n test_by_name').tap do |output|
- assert_match 'by line', output
- assert_match 'by name', output
- assert_match '2 runs, 2 assertions', output
+ run_test_command("test/models/post_test.rb:4 -n test_by_name").tap do |output|
+ assert_match "by line", output
+ assert_match "by name", output
+ assert_match "2 runs, 2 assertions", output
end
end
def test_shows_filtered_backtrace_by_default
create_backtrace_test
- assert_match 'Rails::BacktraceCleaner', run_test_command('test/unit/backtrace_test.rb')
+ assert_match "Rails::BacktraceCleaner", run_test_command("test/unit/backtrace_test.rb")
end
def test_backtrace_option
create_backtrace_test
- assert_match 'Minitest::BacktraceFilter', run_test_command('test/unit/backtrace_test.rb -b')
- assert_match 'Minitest::BacktraceFilter',
- run_test_command('test/unit/backtrace_test.rb --backtrace')
+ assert_match "Minitest::BacktraceFilter", run_test_command("test/unit/backtrace_test.rb -b")
+ assert_match "Minitest::BacktraceFilter",
+ run_test_command("test/unit/backtrace_test.rb --backtrace")
end
def test_show_full_backtrace_using_backtrace_environment_variable
create_backtrace_test
- switch_env 'BACKTRACE', 'true' do
- assert_match 'Minitest::BacktraceFilter', run_test_command('test/unit/backtrace_test.rb')
+ switch_env "BACKTRACE", "true" do
+ assert_match "Minitest::BacktraceFilter", run_test_command("test/unit/backtrace_test.rb")
end
end
def test_run_app_without_rails_loaded
# Simulate a real Rails app boot.
- app_file 'config/boot.rb', <<-RUBY
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
+ app_file "config/boot.rb", <<-RUBY
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
require 'bundler/setup' # Set up gems listed in the Gemfile.
RUBY
- assert_match '0 runs, 0 assertions', run_test_command('')
+ assert_match "0 runs, 0 assertions", run_test_command("")
end
def test_output_inline_by_default
- create_test_file :models, 'post', pass: false
+ create_test_file :models, "post", pass: false, print: false
- output = run_test_command('test/models/post_test.rb')
- expect = %r{Running:\n\nPostTest\nF\n\nFailure:\nPostTest#test_truth \[[^\]]+test/models/post_test.rb:6\]:\nwups!\n\nbin/rails test test/models/post_test.rb:4\n\n\n\n}
+ output = run_test_command("test/models/post_test.rb")
+ expect = %r{Running:\n\nF\n\nFailure:\nPostTest#test_truth \[[^\]]+test/models/post_test.rb:6\]:\nwups!\n\nrails test test/models/post_test.rb:4\n\n\n\n}
assert_match expect, output
end
def test_only_inline_failure_output
- create_test_file :models, 'post', pass: false
+ create_test_file :models, "post", pass: false
- output = run_test_command('test/models/post_test.rb')
- assert_match %r{Finished in.*\n\n1 runs, 1 assertions}, output
+ output = run_test_command("test/models/post_test.rb")
+ assert_match %r{Finished in.*\n1 runs, 1 assertions}, output
end
def test_fail_fast
- create_test_file :models, 'post', pass: false
+ create_test_file :models, "post", pass: false
assert_match(/Interrupt/,
- capture(:stderr) { run_test_command('test/models/post_test.rb --fail-fast') })
+ capture(:stderr) { run_test_command("test/models/post_test.rb --fail-fast", stderr: true) })
+ 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
+ ActiveRecord::Schema.define(version: 1) do
+ create_table :users do |t|
+ t.string :name
+ end
+ end
+ RUBY
+
+ output = run_test_command(file_name)
+
+ assert_match %r{Finished in.*\n2 runs, 2 assertions}, output
+ assert_no_match "create_table(:users)", output
+ end
+
+ def test_run_in_parallel_with_threads
+ exercise_parallelization_regardless_of_machine_core_count(with: :threads)
+
+ file_name = create_parallel_threads_test_file
+
+ app_file "db/schema.rb", <<-RUBY
+ ActiveRecord::Schema.define(version: 1) do
+ create_table :users do |t|
+ t.string :name
+ end
+ end
+ RUBY
+
+ output = run_test_command(file_name)
+
+ assert_match %r{Finished in.*\n2 runs, 2 assertions}, output
+ 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') }
+ error = capture(:stderr) { run_test_command("test/not_exists.rb", stderr: true) }
assert_match(%r{cannot load such file.+test/not_exists\.rb}, error)
end
def test_pass_TEST_env_on_rake_test
- create_test_file :models, 'account'
- create_test_file :models, 'post', pass: false
+ create_test_file :models, "account"
+ create_test_file :models, "post", pass: false
# This specifically verifies TEST for backwards compatibility with rake test
- # as bin/rails test already supports running tests from a single file more cleanly.
- output = Dir.chdir(app_path) { `bin/rake test TEST=test/models/post_test.rb` }
+ # as `rails test` already supports running tests from a single file more cleanly.
+ output = Dir.chdir(app_path) { `bin/rake test TEST=test/models/post_test.rb` }
assert_match "PostTest", output, "passing TEST= should run selected test"
assert_no_match "AccountTest", output, "passing TEST= should only run selected test"
- assert_match '1 runs, 1 assertions', output
+ assert_match "1 runs, 1 assertions", output
+ end
+
+ def test_pass_rake_options
+ create_test_file :models, "account"
+ output = Dir.chdir(app_path) { `bin/rake --rakefile Rakefile --trace=stdout test` }
+
+ assert_match "1 runs, 1 assertions", output
+ assert_match "Execute test", output
end
def test_rails_db_create_all_restores_db_connection
- create_test_file :models, 'account'
- output = Dir.chdir(app_path) { `bin/rails db:create:all db:migrate && echo ".tables" | rails dbconsole` }
+ create_test_file :models, "account"
+ rails "db:create:all", "db:migrate"
+ output = Dir.chdir(app_path) { `echo ".tables" | rails dbconsole` }
assert_match "ar_internal_metadata", output, "tables should be dumped"
end
def test_rails_db_create_all_restores_db_connection_after_drop
- create_test_file :models, 'account'
- Dir.chdir(app_path) { `bin/rails db:create:all` } # create all to avoid warnings
- output = Dir.chdir(app_path) { `bin/rails db:drop:all db:create:all db:migrate && echo ".tables" | rails dbconsole` }
+ create_test_file :models, "account"
+ rails "db:create:all" # create all to avoid warnings
+ rails "db:drop:all", "db:create:all", "db:migrate"
+ output = Dir.chdir(app_path) { `echo ".tables" | rails dbconsole` }
assert_match "ar_internal_metadata", output, "tables should be dumped"
end
def test_rake_passes_TESTOPTS_to_minitest
- create_test_file :models, 'account'
- output = Dir.chdir(app_path) { `bin/rake test TESTOPTS=-v` }
+ create_test_file :models, "account"
+ output = Dir.chdir(app_path) { `bin/rake test TESTOPTS=-v` }
assert_match "AccountTest#test_truth", output, "passing TEST= should run selected test"
end
+ def test_running_with_ruby_gets_test_env_by_default
+ # Subshells inherit `ENV`, so we need to ensure `RAILS_ENV` is set to
+ # nil before we run the tests in the test app.
+ re, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], nil
+
+ file = create_test_for_env("test")
+ results = Dir.chdir(app_path) {
+ `ruby -Ilib:test #{file}`.each_line.map { |line| JSON.parse line }
+ }
+ assert_equal 1, results.length
+ failures = results.first["failures"]
+ flunk(failures.first) unless failures.empty?
+
+ ensure
+ ENV["RAILS_ENV"] = re
+ end
+
+ def test_running_with_ruby_can_set_env_via_cmdline
+ # Subshells inherit `ENV`, so we need to ensure `RAILS_ENV` is set to
+ # nil before we run the tests in the test app.
+ re, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], nil
+
+ file = create_test_for_env("development")
+ results = Dir.chdir(app_path) {
+ `RAILS_ENV=development ruby -Ilib:test #{file}`.each_line.map { |line| JSON.parse line }
+ }
+ assert_equal 1, results.length
+ failures = results.first["failures"]
+ flunk(failures.first) unless failures.empty?
+
+ ensure
+ ENV["RAILS_ENV"] = re
+ end
+
def test_rake_passes_multiple_TESTOPTS_to_minitest
- create_test_file :models, 'account'
- output = Dir.chdir(app_path) { `bin/rake test TESTOPTS='-v --seed=1234'` }
+ create_test_file :models, "account"
+ output = Dir.chdir(app_path) { `bin/rake test TESTOPTS='-v --seed=1234'` }
assert_match "AccountTest#test_truth", output, "passing TEST= should run selected test"
assert_match "seed=1234", output, "passing TEST= should run selected test"
end
+ def test_rake_runs_multiple_test_tasks
+ create_test_file :models, "account"
+ create_test_file :controllers, "accounts_controller"
+ output = Dir.chdir(app_path) { `bin/rake test:models test:controllers TESTOPTS='-v'` }
+ assert_match "AccountTest#test_truth", output
+ assert_match "AccountsControllerTest#test_truth", output
+ end
+
+ def test_rake_db_and_test_tasks_parses_args_correctly
+ create_test_file :models, "account"
+ output = Dir.chdir(app_path) { `bin/rake db:migrate test:models TESTOPTS='-v' && echo ".tables" | rails dbconsole` }
+ assert_match "AccountTest#test_truth", output
+ assert_match "ar_internal_metadata", output
+ end
+
+ def test_warnings_option
+ app_file "test/models/warnings_test.rb", <<-RUBY
+ require 'test_helper'
+ def test_warnings
+ a = 1
+ end
+ RUBY
+ assert_match(/warning: assigned but unused variable/,
+ capture(:stderr) { run_test_command("test/models/warnings_test.rb -w", stderr: true) })
+ end
+
+ 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
+ puts "rollback"
+ super
+ end
+
+ Capybara.singleton_class.prepend(Module.new do
+ def reset_sessions!
+ puts "reset sessions"
+ super
+ end
+ end)
+
+ test "dummy" do
+ end
+ end
+ RUBY
+
+ run_test_command("test/system/reset_session_before_rollback_test.rb").tap do |output|
+ assert_match "reset sessions\nrollback", output
+ assert_match "1 runs, 0 assertions, 0 failures, 0 errors, 0 skips", output
+ 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"
+
+ class DummyTest < ApplicationSystemTestCase
+ test "something" do
+ assert true
+ end
+ end
+ RUBY
+
+ run_test_command("").tap do |output|
+ assert_match "0 runs, 0 assertions, 0 failures, 0 errors, 0 skips", output
+ end
+ end
+
+ def test_system_tests_are_not_run_through_rake_test
+ app_file "test/system/dummy_test.rb", <<-RUBY
+ require "application_system_test_case"
+
+ class DummyTest < ApplicationSystemTestCase
+ test "something" do
+ assert true
+ end
+ end
+ RUBY
+
+ output = Dir.chdir(app_path) { `bin/rake test` }
+ assert_match "0 runs, 0 assertions, 0 failures, 0 errors, 0 skips", output
+ end
+
+ 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
+ assert true
+ end
+ end
+ RUBY
+
+ output = Dir.chdir(app_path) { `bin/rake test TEST=test/system/dummy_test.rb` }
+ assert_match "1 runs, 1 assertions, 0 failures, 0 errors, 0 skips", output
+ end
+
private
- def run_test_command(arguments = 'test/unit/test_test.rb')
- Dir.chdir(app_path) { `bin/rails t #{arguments}` }
+ def run_test_command(arguments = "test/unit/test_test.rb", **opts)
+ rails "t", *Shellwords.split(arguments), allow_failure: true, **opts
end
def create_model_with_fixture
- script 'generate model user name:string'
+ rails "generate", "model", "user", "name:string"
- app_file 'test/fixtures/users.yml', <<-YAML.strip_heredoc
+ app_file "test/fixtures/users.yml", <<~YAML
vampire:
id: 1
name: Koyomi Araragi
@@ -551,7 +864,7 @@ module ApplicationTests
run_migration
end
- def create_fixture_test(path = :unit, name = 'test')
+ def create_fixture_test(path = :unit, name = "test")
app_file "test/#{path}/#{name}_test.rb", <<-RUBY
require 'test_helper'
@@ -564,7 +877,7 @@ module ApplicationTests
end
def create_backtrace_test
- app_file 'test/unit/backtrace_test.rb', <<-RUBY
+ app_file "test/unit/backtrace_test.rb", <<-RUBY
require 'test_helper'
class BacktraceTest < ActiveSupport::TestCase
@@ -576,24 +889,122 @@ module ApplicationTests
end
def create_schema
- app_file 'db/schema.rb', ''
+ app_file "db/schema.rb", ""
end
- def create_test_file(path = :unit, name = 'test', pass: true)
+ def create_test_for_env(env)
+ app_file "test/models/environment_test.rb", <<-RUBY
+ require 'test_helper'
+ class JSONReporter < Minitest::AbstractReporter
+ def record(result)
+ puts JSON.dump(klass: result.class.name,
+ name: result.name,
+ failures: result.failures,
+ assertions: result.assertions,
+ time: result.time)
+ end
+ end
+
+ def Minitest.plugin_json_reporter_init(opts)
+ Minitest.reporter.reporters.clear
+ Minitest.reporter.reporters << JSONReporter.new
+ end
+
+ Minitest.extensions << "rails"
+ Minitest.extensions << "json_reporter"
+
+ # Minitest uses RubyGems to find plugins, and since RubyGems
+ # doesn't know about the Rails installation we're pointing at,
+ # Minitest won't require the Rails minitest plugin when we run
+ # these integration tests. So we have to manually require the
+ # Minitest plugin here.
+ require 'minitest/rails_plugin'
+
+ class EnvironmentTest < ActiveSupport::TestCase
+ def test_environment
+ test_db = ActiveRecord::Base.configurations[#{env.dump}]["database"]
+ db_file = ActiveRecord::Base.connection_config[:database]
+ assert_match(test_db, db_file)
+ assert_equal #{env.dump}, ENV["RAILS_ENV"]
+ end
+ end
+ RUBY
+ end
+
+ def create_test_file(path = :unit, name = "test", pass: true, print: true)
app_file "test/#{path}/#{name}_test.rb", <<-RUBY
require 'test_helper'
class #{name.camelize}Test < ActiveSupport::TestCase
def test_truth
- puts "#{name.camelize}Test"
+ puts "#{name.camelize}Test" if #{print}
assert #{pass}, 'wups!'
end
end
RUBY
end
+ def create_parallel_processes_test_file
+ app_file "test/models/parallel_test.rb", <<-RUBY
+ require 'test_helper'
+
+ class ParallelTest < ActiveSupport::TestCase
+ RD1, WR1 = IO.pipe
+ RD2, WR2 = IO.pipe
+
+ test "one" do
+ WR1.close
+ assert_equal "x", RD1.read(1) # blocks until two runs
+
+ RD2.close
+ WR2.write "y" # Allow two to run
+ WR2.close
+ end
+
+ test "two" do
+ RD1.close
+ WR1.write "x" # Allow one to run
+ WR1.close
+
+ WR2.close
+ assert_equal "y", RD2.read(1) # blocks until one runs
+ end
+ end
+ RUBY
+ end
+
+ def create_parallel_threads_test_file
+ app_file "test/models/parallel_test.rb", <<-RUBY
+ require 'test_helper'
+
+ class ParallelTest < ActiveSupport::TestCase
+ Q1 = Queue.new
+ Q2 = Queue.new
+ test "one" do
+ assert_equal "x", Q1.pop # blocks until two runs
+
+ Q2 << "y"
+ end
+
+ test "two" do
+ Q1 << "x"
+
+ assert_equal "y", Q2.pop # blocks until one runs
+ end
+ end
+ 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
+ app_file "test/unit/env_test.rb", <<-RUBY
require 'test_helper'
class EnvTest < ActiveSupport::TestCase
@@ -605,17 +1016,17 @@ module ApplicationTests
end
def create_scaffold
- script 'generate scaffold user name:string'
- Dir.chdir(app_path) { File.exist?('app/models/user.rb') }
+ rails "generate", "scaffold", "user", "name:string"
+ assert File.exist?("#{app_path}/app/models/user.rb")
run_migration
end
def create_controller
- script 'generate controller admin/dashboard index'
+ rails "generate", "controller", "admin/dashboard", "index"
end
def run_migration
- Dir.chdir(app_path) { `bin/rails db:migrate` }
+ rails "db:migrate"
end
end
end
diff --git a/railties/test/application/test_test.rb b/railties/test/application/test_test.rb
index 85b003fce9..83e63718df 100644
--- a/railties/test/application/test_test.rb
+++ b/railties/test/application/test_test.rb
@@ -1,20 +1,26 @@
-require 'isolation/abstract_unit'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
module ApplicationTests
class TestTest < ActiveSupport::TestCase
include ActiveSupport::Testing::Isolation
def setup
+ @old = ENV["PARALLEL_WORKERS"]
+ ENV["PARALLEL_WORKERS"] = "0"
+
build_app
- boot_rails
end
def teardown
+ ENV["PARALLEL_WORKERS"] = @old
+
teardown_app
end
- test "truth" do
- app_file 'test/unit/foo_test.rb', <<-RUBY
+ test "simple successful test" do
+ app_file "test/unit/foo_test.rb", <<-RUBY
require 'test_helper'
class FooTest < ActiveSupport::TestCase
@@ -24,20 +30,52 @@ module ApplicationTests
end
RUBY
- assert_successful_test_run 'unit/foo_test.rb'
+ assert_successful_test_run "unit/foo_test.rb"
+ end
+
+ test "after_run" do
+ app_file "test/unit/foo_test.rb", <<-RUBY
+ require 'test_helper'
+
+ Minitest.after_run { puts "WORLD" }
+ Minitest.after_run { puts "HELLO" }
+
+ class FooTest < ActiveSupport::TestCase
+ def test_truth
+ assert true
+ end
+ end
+ RUBY
+
+ result = assert_successful_test_run "unit/foo_test.rb"
+ assert_equal ["HELLO", "WORLD"], result.scan(/HELLO|WORLD/) # only once and in correct order
+ end
+
+ test "simple failed test" do
+ app_file "test/unit/foo_test.rb", <<-RUBY
+ require 'test_helper'
+
+ class FooTest < ActiveSupport::TestCase
+ def test_truth
+ assert false
+ end
+ end
+ RUBY
+
+ assert_unsuccessful_run "unit/foo_test.rb", "Failure:\nFooTest#test_truth"
end
test "integration test" do
- controller 'posts', <<-RUBY
+ controller "posts", <<-RUBY
class PostsController < ActionController::Base
end
RUBY
- app_file 'app/views/posts/index.html.erb', <<-HTML
+ app_file "app/views/posts/index.html.erb", <<-HTML
Posts#index
HTML
- app_file 'test/integration/posts_test.rb', <<-RUBY
+ app_file "test/integration/posts_test.rb", <<-RUBY
require 'test_helper'
class PostsTest < ActionDispatch::IntegrationTest
@@ -49,11 +87,11 @@ module ApplicationTests
end
RUBY
- assert_successful_test_run 'integration/posts_test.rb'
+ assert_successful_test_run "integration/posts_test.rb"
end
test "enable full backtraces on test failures" do
- app_file 'test/unit/failing_test.rb', <<-RUBY
+ app_file "test/unit/failing_test.rb", <<-RUBY
require 'test_helper'
class FailingTest < ActiveSupport::TestCase
@@ -63,16 +101,16 @@ module ApplicationTests
end
RUBY
- output = run_test_file('unit/failing_test.rb', env: { "BACKTRACE" => "1" })
+ output = run_test_file("unit/failing_test.rb", env: { "BACKTRACE" => "1" })
assert_match %r{test/unit/failing_test\.rb}, output
assert_match %r{test/unit/failing_test\.rb:4}, output
end
test "ruby schema migrations" do
- output = script('generate model user name:string')
+ output = rails("generate", "model", "user", "name:string")
version = output.match(/(\d+)_create_users\.rb/)[1]
- app_file 'test/models/user_test.rb', <<-RUBY
+ app_file "test/models/user_test.rb", <<-RUBY
require 'test_helper'
class UserTest < ActiveSupport::TestCase
@@ -81,11 +119,11 @@ module ApplicationTests
end
end
RUBY
- app_file 'db/schema.rb', ''
+ app_file "db/schema.rb", ""
assert_unsuccessful_run "models/user_test.rb", "Migrations are pending"
- app_file 'db/schema.rb', <<-RUBY
+ app_file "db/schema.rb", <<-RUBY
ActiveRecord::Schema.define(version: #{version}) do
create_table :users do |t|
t.string :name
@@ -93,7 +131,7 @@ module ApplicationTests
end
RUBY
- app_file 'config/initializers/disable_maintain_test_schema.rb', <<-RUBY
+ app_file "config/initializers/disable_maintain_test_schema.rb", <<-RUBY
Rails.application.config.active_record.maintain_test_schema = false
RUBY
@@ -101,15 +139,15 @@ module ApplicationTests
File.delete "#{app_path}/config/initializers/disable_maintain_test_schema.rb"
- result = assert_successful_test_run('models/user_test.rb')
- assert !result.include?("create_table(:users)")
+ result = assert_successful_test_run("models/user_test.rb")
+ assert_not_includes result, "create_table(:users)"
end
test "sql structure migrations" do
- output = script('generate model user name:string')
+ output = rails("generate", "model", "user", "name:string")
version = output.match(/(\d+)_create_users\.rb/)[1]
- app_file 'test/models/user_test.rb', <<-RUBY
+ app_file "test/models/user_test.rb", <<-RUBY
require 'test_helper'
class UserTest < ActiveSupport::TestCase
@@ -119,21 +157,21 @@ module ApplicationTests
end
RUBY
- app_file 'db/structure.sql', ''
- app_file 'config/initializers/enable_sql_schema_format.rb', <<-RUBY
+ app_file "db/structure.sql", ""
+ app_file "config/initializers/enable_sql_schema_format.rb", <<-RUBY
Rails.application.config.active_record.schema_format = :sql
RUBY
assert_unsuccessful_run "models/user_test.rb", "Migrations are pending"
- app_file 'db/structure.sql', <<-SQL
+ app_file "db/structure.sql", <<-SQL
CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL);
CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version");
CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255));
INSERT INTO schema_migrations (version) VALUES ('#{version}');
SQL
- app_file 'config/initializers/disable_maintain_test_schema.rb', <<-RUBY
+ app_file "config/initializers/disable_maintain_test_schema.rb", <<-RUBY
Rails.application.config.active_record.maintain_test_schema = false
RUBY
@@ -141,14 +179,14 @@ module ApplicationTests
File.delete "#{app_path}/config/initializers/disable_maintain_test_schema.rb"
- assert_successful_test_run('models/user_test.rb')
+ assert_successful_test_run("models/user_test.rb")
end
test "sql structure migrations when adding column to existing table" do
- output_1 = script('generate model user name:string')
+ output_1 = rails("generate", "model", "user", "name:string")
version_1 = output_1.match(/(\d+)_create_users\.rb/)[1]
- app_file 'test/models/user_test.rb', <<-RUBY
+ app_file "test/models/user_test.rb", <<-RUBY
require 'test_helper'
class UserTest < ActiveSupport::TestCase
test "user" do
@@ -157,23 +195,23 @@ module ApplicationTests
end
RUBY
- app_file 'config/initializers/enable_sql_schema_format.rb', <<-RUBY
+ app_file "config/initializers/enable_sql_schema_format.rb", <<-RUBY
Rails.application.config.active_record.schema_format = :sql
RUBY
- app_file 'db/structure.sql', <<-SQL
+ app_file "db/structure.sql", <<-SQL
CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL);
CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version");
CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255));
INSERT INTO schema_migrations (version) VALUES ('#{version_1}');
SQL
- assert_successful_test_run('models/user_test.rb')
+ assert_successful_test_run("models/user_test.rb")
- output_2 = script('generate migration add_email_to_users')
+ output_2 = rails("generate", "migration", "add_email_to_users")
version_2 = output_2.match(/(\d+)_add_email_to_users\.rb/)[1]
- app_file 'test/models/user_test.rb', <<-RUBY
+ app_file "test/models/user_test.rb", <<-RUBY
require 'test_helper'
class UserTest < ActiveSupport::TestCase
@@ -183,7 +221,7 @@ module ApplicationTests
end
RUBY
- app_file 'db/structure.sql', <<-SQL
+ app_file "db/structure.sql", <<-SQL
CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL);
CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version");
CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255), "email" varchar(255));
@@ -191,17 +229,17 @@ module ApplicationTests
INSERT INTO schema_migrations (version) VALUES ('#{version_2}');
SQL
- assert_successful_test_run('models/user_test.rb')
+ assert_successful_test_run("models/user_test.rb")
end
# TODO: would be nice if we could detect the schema change automatically.
# For now, the user has to synchronize the schema manually.
- # This test-case serves as a reminder for this use-case.
+ # This test case serves as a reminder for this use case.
test "manually synchronize test schema after rollback" do
- output = script('generate model user name:string')
+ output = rails("generate", "model", "user", "name:string")
version = output.match(/(\d+)_create_users\.rb/)[1]
- app_file 'test/models/user_test.rb', <<-RUBY
+ app_file "test/models/user_test.rb", <<-RUBY
require 'test_helper'
class UserTest < ActiveSupport::TestCase
@@ -210,7 +248,7 @@ module ApplicationTests
end
end
RUBY
- app_file 'db/schema.rb', <<-RUBY
+ app_file "db/schema.rb", <<-RUBY
ActiveRecord::Schema.define(version: #{version}) do
create_table :users do |t|
t.string :name
@@ -221,7 +259,7 @@ module ApplicationTests
assert_successful_test_run "models/user_test.rb"
# Simulate `db:rollback` + edit of the migration file + `db:migrate`
- app_file 'db/schema.rb', <<-RUBY
+ app_file "db/schema.rb", <<-RUBY
ActiveRecord::Schema.define(version: #{version}) do
create_table :users do |t|
t.string :name
@@ -232,7 +270,7 @@ module ApplicationTests
assert_successful_test_run "models/user_test.rb"
- Dir.chdir(app_path) { `bin/rails db:test:prepare` }
+ rails "db:test:prepare"
assert_unsuccessful_run "models/user_test.rb", <<-ASSERTION
Expected: ["id", "name"]
@@ -241,10 +279,10 @@ Expected: ["id", "name"]
end
test "hooks for plugins" do
- output = script('generate model user name:string')
+ output = rails("generate", "model", "user", "name:string")
version = output.match(/(\d+)_create_users\.rb/)[1]
- app_file 'lib/tasks/hooks.rake', <<-RUBY
+ app_file "lib/tasks/hooks.rake", <<-RUBY
task :before_hook do
has_user_table = ActiveRecord::Base.connection.table_exists?('users')
puts "before: " + has_user_table.to_s
@@ -259,7 +297,7 @@ Expected: ["id", "name"]
Rake::Task[:after_hook].invoke
end
RUBY
- app_file 'test/models/user_test.rb', <<-RUBY
+ app_file "test/models/user_test.rb", <<-RUBY
require 'test_helper'
class UserTest < ActiveSupport::TestCase
test "user" do
@@ -269,7 +307,7 @@ Expected: ["id", "name"]
RUBY
# Simulate `db:migrate`
- app_file 'db/schema.rb', <<-RUBY
+ app_file "db/schema.rb", <<-RUBY
ActiveRecord::Schema.define(version: #{version}) do
create_table :users do |t|
t.string :name
@@ -290,7 +328,7 @@ Expected: ["id", "name"]
def assert_unsuccessful_run(name, message)
result = run_test_file(name)
assert_not_equal 0, $?.to_i
- assert result.include?(message)
+ assert_includes result, message
result
end
@@ -301,7 +339,7 @@ Expected: ["id", "name"]
end
def run_test_file(name, options = {})
- Dir.chdir(app_path) { `bin/rails test "#{app_path}/test/#{name}" 2>&1` }
+ rails "test", "#{app_path}/test/#{name}", allow_failure: true
end
end
end
diff --git a/railties/test/application/url_generation_test.rb b/railties/test/application/url_generation_test.rb
index 894e18cb39..dc737089f6 100644
--- a/railties/test/application/url_generation_test.rb
+++ b/railties/test/application/url_generation_test.rb
@@ -1,4 +1,6 @@
-require 'isolation/abstract_unit'
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
module ApplicationTests
class UrlGenerationTest < ActiveSupport::TestCase
@@ -9,16 +11,16 @@ module ApplicationTests
end
test "it works" do
- boot_rails
require "rails"
require "action_controller/railtie"
require "action_view/railtie"
class MyApp < Rails::Application
- secrets.secret_key_base = "3b7cd727ee24e8444053437c36cc66c4"
config.session_store :cookie_store, key: "_myapp_session"
config.active_support.deprecation = :log
config.eager_load = false
+ config.hosts << proc { true }
+ config.secret_key_base = "b3c631c314c0bbca50c1b2843150fe33"
end
Rails.application.initialize!
@@ -28,7 +30,7 @@ module ApplicationTests
class ::OmgController < ::ApplicationController
def index
- render text: omg_path
+ render plain: omg_path
end
end
@@ -36,7 +38,7 @@ module ApplicationTests
get "/" => "omg#index", as: :omg
end
- require 'rack/test'
+ require "rack/test"
extend Rack::Test::Methods
get "/"
@@ -44,12 +46,11 @@ module ApplicationTests
end
def test_routes_know_the_relative_root
- boot_rails
require "rails"
require "action_controller/railtie"
require "action_view/railtie"
- relative_url = '/hello'
+ relative_url = "/hello"
ENV["RAILS_RELATIVE_URL_ROOT"] = relative_url
app = Class.new(Rails::Application)
assert_equal relative_url, app.routes.relative_url_root
diff --git a/railties/test/application/version_test.rb b/railties/test/application/version_test.rb
new file mode 100644
index 0000000000..ae85cf8f05
--- /dev/null
+++ b/railties/test/application/version_test.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "rails/gem_version"
+
+class VersionTest < ActiveSupport::TestCase
+ include ActiveSupport::Testing::Isolation
+
+ def setup
+ build_app
+ end
+
+ def teardown
+ teardown_app
+ end
+
+ test "command works" do
+ output = rails("version")
+ assert_equal "Rails #{Rails.gem_version}\n", output
+ end
+
+ test "short-cut alias works" do
+ output = rails("-v")
+ assert_equal "Rails #{Rails.gem_version}\n", output
+ end
+end
diff --git a/railties/test/application/zeitwerk_integration_test.rb b/railties/test/application/zeitwerk_integration_test.rb
new file mode 100644
index 0000000000..5d2e34433a
--- /dev/null
+++ b/railties/test/application/zeitwerk_integration_test.rb
@@ -0,0 +1,304 @@
+# 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 code in engines" do
+ $test_blog_engine_eager_loaded = false
+
+ engine("blog") do |bukkit|
+ bukkit.write("lib/blog.rb", "class BlogEngine < Rails::Engine; end")
+ bukkit.write("app/models/post.rb", "Post = $test_blog_engine_eager_loaded = true")
+ end
+
+ boot("production")
+
+ assert $test_blog_engine_eager_loaded
+ end
+
+ 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 directories not present in eager load paths are not eager loaded" do
+ $zeitwerk_integration_test_user = false
+ app_file "app/models/user.rb", "class User; end; $zeitwerk_integration_test_user = true"
+
+ $zeitwerk_integration_test_lib = false
+ app_dir "lib"
+ app_file "lib/webhook_hacks.rb", "WebhookHacks = 1; $zeitwerk_integration_test_lib = true"
+
+ $zeitwerk_integration_test_extras = false
+ app_dir "extras"
+ app_file "extras/websocket_hacks.rb", "WebsocketHacks = 1; $zeitwerk_integration_test_extras = true"
+
+ add_to_config "config.autoload_paths << '#{app_path}/lib'"
+ add_to_config "config.autoload_once_paths << '#{app_path}/extras'"
+
+ boot("production")
+
+ assert $zeitwerk_integration_test_user
+ assert !$zeitwerk_integration_test_lib
+ assert !$zeitwerk_integration_test_extras
+
+ assert WebhookHacks
+ assert WebsocketHacks
+
+ assert $zeitwerk_integration_test_lib
+ assert $zeitwerk_integration_test_extras
+ end
+
+ test "autoload_paths are set as root dirs of main, and in the same order" do
+ boot
+
+ existing_autoload_paths = deps.autoload_paths.select { |dir| File.directory?(dir) }
+ assert_equal existing_autoload_paths, Rails.autoloaders.main.dirs
+ end
+
+ test "autoload_once_paths go to the once autoloader, and in the same order" do
+ extras = %w(e1 e2 e3)
+ extras.each do |extra|
+ app_dir extra
+ add_to_config %(config.autoload_once_paths << "\#{Rails.root}/#{extra}")
+ end
+
+ boot
+
+ extras = extras.map { |extra| "#{app_path}/#{extra}" }
+ extras.each do |extra|
+ assert_not_includes Rails.autoloaders.main.dirs, extra
+ end
+ assert_equal extras, Rails.autoloaders.once.dirs
+ 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