aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/test/dispatch
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/test/dispatch')
-rw-r--r--actionpack/test/dispatch/cookies_test.rb269
-rw-r--r--actionpack/test/dispatch/debug_exceptions_test.rb38
-rw-r--r--actionpack/test/dispatch/header_test.rb2
-rw-r--r--actionpack/test/dispatch/live_response_test.rb15
-rw-r--r--actionpack/test/dispatch/mapper_test.rb6
-rw-r--r--actionpack/test/dispatch/mime_type_test.rb8
-rw-r--r--actionpack/test/dispatch/mount_test.rb21
-rw-r--r--actionpack/test/dispatch/prefix_generation_test.rb155
-rw-r--r--actionpack/test/dispatch/rack_test.rb191
-rw-r--r--actionpack/test/dispatch/reloader_test.rb5
-rw-r--r--actionpack/test/dispatch/request/json_params_parsing_test.rb7
-rw-r--r--actionpack/test/dispatch/request/multipart_params_parsing_test.rb4
-rw-r--r--actionpack/test/dispatch/request/query_string_parsing_test.rb31
-rw-r--r--actionpack/test/dispatch/request/session_test.rb57
-rw-r--r--actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb5
-rw-r--r--actionpack/test/dispatch/request_test.rb610
-rw-r--r--actionpack/test/dispatch/response_test.rb24
-rw-r--r--actionpack/test/dispatch/routing/inspector_test.rb90
-rw-r--r--actionpack/test/dispatch/routing/route_set_test.rb4
-rw-r--r--actionpack/test/dispatch/routing_test.rb727
-rw-r--r--actionpack/test/dispatch/session/mem_cache_store_test.rb21
-rw-r--r--actionpack/test/dispatch/ssl_test.rb7
-rw-r--r--actionpack/test/dispatch/static_test.rb30
-rw-r--r--actionpack/test/dispatch/uploaded_file_test.rb6
-rw-r--r--actionpack/test/dispatch/url_generation_test.rb32
25 files changed, 1862 insertions, 503 deletions
diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb
index 91ac13e7c6..0f145666d1 100644
--- a/actionpack/test/dispatch/cookies_test.rb
+++ b/actionpack/test/dispatch/cookies_test.rb
@@ -11,6 +11,16 @@ require 'active_support/key_generator'
require 'active_support/message_verifier'
class CookiesTest < ActionController::TestCase
+ class CustomSerializer
+ def self.load(value)
+ value.to_s + " and loaded"
+ end
+
+ def self.dump(value)
+ value.to_s + " was dumped"
+ end
+ end
+
class TestController < ActionController::Base
def authenticate
cookies["user_name"] = "david"
@@ -359,9 +369,72 @@ class CookiesTest < ActionController::TestCase
assert_equal 'Jamie', @controller.send(:cookies).permanent[:user_name]
end
- def test_signed_cookie
+ def test_signed_cookie_using_default_serializer
get :set_signed_cookie
- assert_equal 45, @controller.send(:cookies).signed[:user_id]
+ cookies = @controller.send :cookies
+ assert_not_equal 45, cookies[:user_id]
+ assert_equal 45, cookies.signed[:user_id]
+ end
+
+ def test_signed_cookie_using_marshal_serializer
+ @request.env["action_dispatch.cookies_serializer"] = :marshal
+ get :set_signed_cookie
+ cookies = @controller.send :cookies
+ assert_not_equal 45, cookies[:user_id]
+ assert_equal 45, cookies.signed[:user_id]
+ end
+
+ def test_signed_cookie_using_json_serializer
+ @request.env["action_dispatch.cookies_serializer"] = :json
+ get :set_signed_cookie
+ cookies = @controller.send :cookies
+ assert_not_equal 45, cookies[:user_id]
+ assert_equal 45, cookies.signed[:user_id]
+ end
+
+ def test_signed_cookie_using_custom_serializer
+ @request.env["action_dispatch.cookies_serializer"] = CustomSerializer
+ get :set_signed_cookie
+ assert_not_equal 45, cookies[:user_id]
+ assert_equal '45 was dumped and loaded', cookies.signed[:user_id]
+ end
+
+ def test_signed_cookie_using_hybrid_serializer_can_migrate_marshal_dumped_value_to_json
+ @request.env["action_dispatch.cookies_serializer"] = :hybrid
+
+ key_generator = @request.env["action_dispatch.key_generator"]
+ signed_cookie_salt = @request.env["action_dispatch.signed_cookie_salt"]
+ secret = key_generator.generate_key(signed_cookie_salt)
+
+ marshal_value = ActiveSupport::MessageVerifier.new(secret, serializer: Marshal).generate(45)
+ @request.headers["Cookie"] = "user_id=#{marshal_value}"
+
+ get :get_signed_cookie
+
+ cookies = @controller.send :cookies
+ assert_not_equal 45, cookies[:user_id]
+ assert_equal 45, cookies.signed[:user_id]
+
+ verifier = ActiveSupport::MessageVerifier.new(secret, serializer: JSON)
+ assert_equal 45, verifier.verify(@response.cookies['user_id'])
+ end
+
+ def test_signed_cookie_using_hybrid_serializer_can_read_from_json_dumped_value
+ @request.env["action_dispatch.cookies_serializer"] = :hybrid
+
+ key_generator = @request.env["action_dispatch.key_generator"]
+ signed_cookie_salt = @request.env["action_dispatch.signed_cookie_salt"]
+ secret = key_generator.generate_key(signed_cookie_salt)
+ json_value = ActiveSupport::MessageVerifier.new(secret, serializer: JSON).generate(45)
+ @request.headers["Cookie"] = "user_id=#{json_value}"
+
+ get :get_signed_cookie
+
+ cookies = @controller.send :cookies
+ assert_not_equal 45, cookies[:user_id]
+ assert_equal 45, cookies.signed[:user_id]
+
+ assert_nil @response.cookies["user_id"]
end
def test_accessing_nonexistant_signed_cookie_should_not_raise_an_invalid_signature
@@ -369,7 +442,18 @@ class CookiesTest < ActionController::TestCase
assert_nil @controller.send(:cookies).signed[:non_existant_attribute]
end
- def test_encrypted_cookie
+ def test_encrypted_cookie_using_default_serializer
+ get :set_encrypted_cookie
+ cookies = @controller.send :cookies
+ assert_not_equal 'bar', cookies[:foo]
+ assert_raise TypeError do
+ cookies.signed[:foo]
+ end
+ assert_equal 'bar', cookies.encrypted[:foo]
+ end
+
+ def test_encrypted_cookie_using_marshal_serializer
+ @request.env["action_dispatch.cookies_serializer"] = :marshal
get :set_encrypted_cookie
cookies = @controller.send :cookies
assert_not_equal 'bar', cookies[:foo]
@@ -379,6 +463,66 @@ class CookiesTest < ActionController::TestCase
assert_equal 'bar', cookies.encrypted[:foo]
end
+ def test_encrypted_cookie_using_json_serializer
+ @request.env["action_dispatch.cookies_serializer"] = :json
+ get :set_encrypted_cookie
+ cookies = @controller.send :cookies
+ assert_not_equal 'bar', cookies[:foo]
+ assert_raises ::JSON::ParserError do
+ cookies.signed[:foo]
+ end
+ assert_equal 'bar', cookies.encrypted[:foo]
+ end
+
+ def test_encrypted_cookie_using_custom_serializer
+ @request.env["action_dispatch.cookies_serializer"] = CustomSerializer
+ get :set_encrypted_cookie
+ assert_not_equal 'bar', cookies.encrypted[:foo]
+ assert_equal 'bar was dumped and loaded', cookies.encrypted[:foo]
+ end
+
+ def test_encrypted_cookie_using_hybrid_serializer_can_migrate_marshal_dumped_value_to_json
+ @request.env["action_dispatch.cookies_serializer"] = :hybrid
+
+ key_generator = @request.env["action_dispatch.key_generator"]
+ encrypted_cookie_salt = @request.env["action_dispatch.encrypted_cookie_salt"]
+ encrypted_signed_cookie_salt = @request.env["action_dispatch.encrypted_signed_cookie_salt"]
+ secret = key_generator.generate_key(encrypted_cookie_salt)
+ sign_secret = key_generator.generate_key(encrypted_signed_cookie_salt)
+
+ marshal_value = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: Marshal).encrypt_and_sign("bar")
+ @request.headers["Cookie"] = "foo=#{marshal_value}"
+
+ get :get_encrypted_cookie
+
+ cookies = @controller.send :cookies
+ assert_not_equal "bar", cookies[:foo]
+ assert_equal "bar", cookies.encrypted[:foo]
+
+ encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON)
+ assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"])
+ end
+
+ def test_encrypted_cookie_using_hybrid_serializer_can_read_from_json_dumped_value
+ @request.env["action_dispatch.cookies_serializer"] = :hybrid
+
+ key_generator = @request.env["action_dispatch.key_generator"]
+ encrypted_cookie_salt = @request.env["action_dispatch.encrypted_cookie_salt"]
+ encrypted_signed_cookie_salt = @request.env["action_dispatch.encrypted_signed_cookie_salt"]
+ secret = key_generator.generate_key(encrypted_cookie_salt)
+ sign_secret = key_generator.generate_key(encrypted_signed_cookie_salt)
+ json_value = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON).encrypt_and_sign("bar")
+ @request.headers["Cookie"] = "foo=#{json_value}"
+
+ get :get_encrypted_cookie
+
+ cookies = @controller.send :cookies
+ assert_not_equal "bar", cookies[:foo]
+ assert_equal "bar", cookies.encrypted[:foo]
+
+ assert_nil @response.cookies["foo"]
+ end
+
def test_accessing_nonexistant_encrypted_cookie_should_not_raise_invalid_message
get :set_encrypted_cookie
assert_nil @controller.send(:cookies).encrypted[:non_existant_attribute]
@@ -537,6 +681,123 @@ class CookiesTest < ActionController::TestCase
assert_equal 'bar', encryptor.decrypt_and_verify(@response.cookies["foo"])
end
+ def test_legacy_json_signed_cookie_is_read_and_transparently_upgraded_by_signed_json_cookie_jar_if_both_secret_token_and_secret_key_base_are_set
+ @request.env["action_dispatch.cookies_serializer"] = :json
+ @request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
+ @request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
+
+ legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33", serializer: JSON).generate(45)
+
+ @request.headers["Cookie"] = "user_id=#{legacy_value}"
+ get :get_signed_cookie
+
+ assert_equal 45, @controller.send(:cookies).signed[:user_id]
+
+ key_generator = @request.env["action_dispatch.key_generator"]
+ secret = key_generator.generate_key(@request.env["action_dispatch.signed_cookie_salt"])
+ verifier = ActiveSupport::MessageVerifier.new(secret, serializer: JSON)
+ assert_equal 45, verifier.verify(@response.cookies["user_id"])
+ end
+
+ def test_legacy_json_signed_cookie_is_read_and_transparently_encrypted_by_encrypted_json_cookie_jar_if_both_secret_token_and_secret_key_base_are_set
+ @request.env["action_dispatch.cookies_serializer"] = :json
+ @request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
+ @request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
+ @request.env["action_dispatch.encrypted_cookie_salt"] = "4433796b79d99a7735553e316522acee"
+ @request.env["action_dispatch.encrypted_signed_cookie_salt"] = "00646eb40062e1b1deff205a27cd30f9"
+
+ legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33", serializer: JSON).generate('bar')
+
+ @request.headers["Cookie"] = "foo=#{legacy_value}"
+ get :get_encrypted_cookie
+
+ assert_equal 'bar', @controller.send(:cookies).encrypted[:foo]
+
+ key_generator = @request.env["action_dispatch.key_generator"]
+ secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"])
+ sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
+ encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON)
+ assert_equal 'bar', encryptor.decrypt_and_verify(@response.cookies["foo"])
+ end
+
+ def test_legacy_json_signed_cookie_is_read_and_transparently_upgraded_by_signed_json_hybrid_jar_if_both_secret_token_and_secret_key_base_are_set
+ @request.env["action_dispatch.cookies_serializer"] = :hybrid
+ @request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
+ @request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
+
+ legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33", serializer: JSON).generate(45)
+
+ @request.headers["Cookie"] = "user_id=#{legacy_value}"
+ get :get_signed_cookie
+
+ assert_equal 45, @controller.send(:cookies).signed[:user_id]
+
+ key_generator = @request.env["action_dispatch.key_generator"]
+ secret = key_generator.generate_key(@request.env["action_dispatch.signed_cookie_salt"])
+ verifier = ActiveSupport::MessageVerifier.new(secret, serializer: JSON)
+ assert_equal 45, verifier.verify(@response.cookies["user_id"])
+ end
+
+ def test_legacy_json_signed_cookie_is_read_and_transparently_encrypted_by_encrypted_hybrid_cookie_jar_if_both_secret_token_and_secret_key_base_are_set
+ @request.env["action_dispatch.cookies_serializer"] = :hybrid
+ @request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
+ @request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
+ @request.env["action_dispatch.encrypted_cookie_salt"] = "4433796b79d99a7735553e316522acee"
+ @request.env["action_dispatch.encrypted_signed_cookie_salt"] = "00646eb40062e1b1deff205a27cd30f9"
+
+ legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33", serializer: JSON).generate('bar')
+
+ @request.headers["Cookie"] = "foo=#{legacy_value}"
+ get :get_encrypted_cookie
+
+ assert_equal 'bar', @controller.send(:cookies).encrypted[:foo]
+
+ key_generator = @request.env["action_dispatch.key_generator"]
+ secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"])
+ sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
+ encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON)
+ assert_equal 'bar', encryptor.decrypt_and_verify(@response.cookies["foo"])
+ end
+
+ def test_legacy_marshal_signed_cookie_is_read_and_transparently_upgraded_by_signed_json_hybrid_jar_if_both_secret_token_and_secret_key_base_are_set
+ @request.env["action_dispatch.cookies_serializer"] = :hybrid
+ @request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
+ @request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
+
+ legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33").generate(45)
+
+ @request.headers["Cookie"] = "user_id=#{legacy_value}"
+ get :get_signed_cookie
+
+ assert_equal 45, @controller.send(:cookies).signed[:user_id]
+
+ key_generator = @request.env["action_dispatch.key_generator"]
+ secret = key_generator.generate_key(@request.env["action_dispatch.signed_cookie_salt"])
+ verifier = ActiveSupport::MessageVerifier.new(secret, serializer: JSON)
+ assert_equal 45, verifier.verify(@response.cookies["user_id"])
+ end
+
+ def test_legacy_marshal_signed_cookie_is_read_and_transparently_encrypted_by_encrypted_hybrid_cookie_jar_if_both_secret_token_and_secret_key_base_are_set
+ @request.env["action_dispatch.cookies_serializer"] = :hybrid
+ @request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
+ @request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
+ @request.env["action_dispatch.encrypted_cookie_salt"] = "4433796b79d99a7735553e316522acee"
+ @request.env["action_dispatch.encrypted_signed_cookie_salt"] = "00646eb40062e1b1deff205a27cd30f9"
+
+ legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33").generate('bar')
+
+ @request.headers["Cookie"] = "foo=#{legacy_value}"
+ get :get_encrypted_cookie
+
+ assert_equal 'bar', @controller.send(:cookies).encrypted[:foo]
+
+ key_generator = @request.env["action_dispatch.key_generator"]
+ secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"])
+ sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
+ encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON)
+ assert_equal 'bar', encryptor.decrypt_and_verify(@response.cookies["foo"])
+ end
+
def test_legacy_signed_cookie_is_treated_as_nil_by_signed_cookie_jar_if_tampered
@request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
@request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
@@ -694,8 +955,6 @@ class CookiesTest < ActionController::TestCase
assert_equal "dhh", cookies['user_name']
end
-
-
def test_setting_request_cookies_is_indifferent_access
cookies.clear
cookies[:user_name] = "andrew"
diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb
index 3045a07ad6..8660deb634 100644
--- a/actionpack/test/dispatch/debug_exceptions_test.rb
+++ b/actionpack/test/dispatch/debug_exceptions_test.rb
@@ -43,6 +43,19 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
raise ActionController::UrlGenerationError, "No route matches"
when "/parameter_missing"
raise ActionController::ParameterMissing, :missing_param_key
+ when "/original_syntax_error"
+ eval 'broke_syntax =' # `eval` need for raise native SyntaxError at runtime
+ when "/syntax_error_into_view"
+ begin
+ eval 'broke_syntax ='
+ rescue Exception => e
+ template = ActionView::Template.new(File.read(__FILE__),
+ __FILE__,
+ ActionView::Template::Handlers::Raw.new,
+ {})
+ raise ActionView::Template::Error.new(template, e)
+ end
+
else
raise "puke!"
end
@@ -134,9 +147,10 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
get "/", {}, xhr_request_env
assert_response 500
+ assert_no_match(/<header>/, body)
assert_no_match(/<body>/, body)
assert_equal response.content_type, "text/plain"
- assert_match(/puke/, body)
+ assert_match(/RuntimeError\npuke/, body)
get "/not_found", {}, xhr_request_env
assert_response 404
@@ -242,4 +256,26 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
get "/", {}, env
assert_operator((output.rewind && output.read).lines.count, :>, 10)
end
+
+ test 'display backtrace when error type is SyntaxError' do
+ @app = DevelopmentApp
+
+ get '/original_syntax_error', {}, {'action_dispatch.backtrace_cleaner' => ActiveSupport::BacktraceCleaner.new}
+
+ assert_response 500
+ assert_select '#Application-Trace' do
+ assert_select 'pre code', /\(eval\):1: syntax error, unexpected/
+ end
+ end
+
+ test 'display backtrace when error type is SyntaxError wrapped by ActionView::Template::Error' do
+ @app = DevelopmentApp
+
+ get '/syntax_error_into_view', {}, {'action_dispatch.backtrace_cleaner' => ActiveSupport::BacktraceCleaner.new}
+
+ assert_response 500
+ assert_select '#Application-Trace' do
+ assert_select 'pre code', /\(eval\):1: syntax error, unexpected/
+ end
+ end
end
diff --git a/actionpack/test/dispatch/header_test.rb b/actionpack/test/dispatch/header_test.rb
index 9e37b96951..e2b38c23bc 100644
--- a/actionpack/test/dispatch/header_test.rb
+++ b/actionpack/test/dispatch/header_test.rb
@@ -55,6 +55,8 @@ class HeaderTest < ActiveSupport::TestCase
test "key?" do
assert @headers.key?("CONTENT_TYPE")
assert @headers.include?("CONTENT_TYPE")
+ assert @headers.key?("Content-Type")
+ assert @headers.include?("Content-Type")
end
test "fetch with block" do
diff --git a/actionpack/test/dispatch/live_response_test.rb b/actionpack/test/dispatch/live_response_test.rb
index e0cfb73acf..512f3a8a7a 100644
--- a/actionpack/test/dispatch/live_response_test.rb
+++ b/actionpack/test/dispatch/live_response_test.rb
@@ -6,6 +6,7 @@ module ActionController
class ResponseTest < ActiveSupport::TestCase
def setup
@response = Live::Response.new
+ @response.request = ActionDispatch::Request.new({}) #yolo
end
def test_header_merge
@@ -34,6 +35,7 @@ module ActionController
@response.stream.close
}
+ @response.await_commit
@response.each do |part|
assert_equal 'foo', part
latch.release
@@ -58,21 +60,30 @@ module ActionController
assert_nil @response.headers['Content-Length']
end
- def test_headers_cannot_be_written_after_write
+ def test_headers_cannot_be_written_after_webserver_reads
@response.stream.write 'omg'
+ latch = ActiveSupport::Concurrency::Latch.new
+ t = Thread.new {
+ @response.stream.each do |chunk|
+ latch.release
+ end
+ }
+
+ latch.await
assert @response.headers.frozen?
e = assert_raises(ActionDispatch::IllegalStateError) do
@response.headers['Content-Length'] = "zomg"
end
assert_equal 'header already sent', e.message
+ @response.stream.close
+ t.join
end
def test_headers_cannot_be_written_after_close
@response.stream.close
- assert @response.headers.frozen?
e = assert_raises(ActionDispatch::IllegalStateError) do
@response.headers['Content-Length'] = "zomg"
end
diff --git a/actionpack/test/dispatch/mapper_test.rb b/actionpack/test/dispatch/mapper_test.rb
index 58457b0c28..d8d3209dac 100644
--- a/actionpack/test/dispatch/mapper_test.rb
+++ b/actionpack/test/dispatch/mapper_test.rb
@@ -38,7 +38,7 @@ module ActionDispatch
def test_mapping_requirements
options = { :controller => 'foo', :action => 'bar', :via => :get }
- m = Mapper::Mapping.new FakeSet.new, {}, '/store/:name(*rest)', options
+ m = Mapper::Mapping.build({}, '/store/:name(*rest)', options)
_, _, requirements, _ = m.to_route
assert_equal(/.+?/, requirements[:rest])
end
@@ -72,7 +72,7 @@ module ActionDispatch
mapper = Mapper.new fakeset
mapper.get '/*path/foo/:bar', :to => 'pages#show'
assert_equal '/*path/foo/:bar(.:format)', fakeset.conditions.first[:path_info]
- assert_nil fakeset.requirements.first[:path]
+ assert_equal(/.+?/, fakeset.requirements.first[:path])
end
def test_map_wildcard_with_multiple_wildcard
@@ -80,7 +80,7 @@ module ActionDispatch
mapper = Mapper.new fakeset
mapper.get '/*foo/*bar', :to => 'pages#show'
assert_equal '/*foo/*bar(.:format)', fakeset.conditions.first[:path_info]
- assert_nil fakeset.requirements.first[:foo]
+ assert_equal(/.+?/, fakeset.requirements.first[:foo])
assert_equal(/.+?/, fakeset.requirements.first[:bar])
end
diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb
index 8a19129695..d29cc8473e 100644
--- a/actionpack/test/dispatch/mime_type_test.rb
+++ b/actionpack/test/dispatch/mime_type_test.rb
@@ -1,8 +1,6 @@
require 'abstract_unit'
class MimeTypeTest < ActiveSupport::TestCase
- Mime::Type.register "image/png", :png unless defined? Mime::PNG
- Mime::Type.register "application/pdf", :pdf unless defined? Mime::PDF
test "parse single" do
Mime::LOOKUP.keys.each do |mime_type|
@@ -31,21 +29,21 @@ class MimeTypeTest < ActiveSupport::TestCase
test "parse text with trailing star at the beginning" do
accept = "text/*, text/html, application/json, multipart/form-data"
- expect = [Mime::HTML, Mime::TEXT, Mime::JS, Mime::CSS, Mime::ICS, Mime::CSV, Mime::XML, Mime::YAML, Mime::JSON, Mime::MULTIPART_FORM]
+ expect = [Mime::HTML, Mime::TEXT, Mime::JS, Mime::CSS, Mime::ICS, Mime::CSV, Mime::VCF, Mime::XML, Mime::YAML, Mime::JSON, Mime::MULTIPART_FORM]
parsed = Mime::Type.parse(accept)
assert_equal expect, parsed
end
test "parse text with trailing star in the end" do
accept = "text/html, application/json, multipart/form-data, text/*"
- expect = [Mime::HTML, Mime::JSON, Mime::MULTIPART_FORM, Mime::TEXT, Mime::JS, Mime::CSS, Mime::ICS, Mime::CSV, Mime::XML, Mime::YAML]
+ expect = [Mime::HTML, Mime::JSON, Mime::MULTIPART_FORM, Mime::TEXT, Mime::JS, Mime::CSS, Mime::ICS, Mime::CSV, Mime::VCF, Mime::XML, Mime::YAML]
parsed = Mime::Type.parse(accept)
assert_equal expect, parsed
end
test "parse text with trailing star" do
accept = "text/*"
- expect = [Mime::HTML, Mime::TEXT, Mime::JS, Mime::CSS, Mime::ICS, Mime::CSV, Mime::XML, Mime::YAML, Mime::JSON]
+ expect = [Mime::HTML, Mime::TEXT, Mime::JS, Mime::CSS, Mime::ICS, Mime::CSV, Mime::VCF, Mime::XML, Mime::YAML, Mime::JSON]
parsed = Mime::Type.parse(accept)
assert_equal expect, parsed
end
diff --git a/actionpack/test/dispatch/mount_test.rb b/actionpack/test/dispatch/mount_test.rb
index 30e95a0b75..bd3f6274de 100644
--- a/actionpack/test/dispatch/mount_test.rb
+++ b/actionpack/test/dispatch/mount_test.rb
@@ -5,7 +5,7 @@ class TestRoutingMount < ActionDispatch::IntegrationTest
class FakeEngine
def self.routes
- Object.new
+ @routes ||= ActionDispatch::Routing::RouteSet.new
end
def self.call(env)
@@ -27,15 +27,28 @@ class TestRoutingMount < ActionDispatch::IntegrationTest
scope "/its_a" do
mount SprocketsApp, :at => "/sprocket"
end
+
+ resources :users do
+ mount FakeEngine, :at => "/fakeengine", :as => :fake_mounted_at_resource
+ end
+
+ mount SprocketsApp, :at => "/", :via => :get
end
def app
Router
end
- def test_trailing_slash_is_not_removed_from_path_info
- get "/sprockets/omg/"
- assert_equal "/sprockets -- /omg/", response.body
+ def test_app_name_is_properly_generated_when_engine_is_mounted_in_resources
+ assert Router.mounted_helpers.method_defined?(:user_fake_mounted_at_resource),
+ "A mounted helper should be defined with a parent's prefix"
+ assert Router.named_routes.routes[:user_fake_mounted_at_resource],
+ "A named route should be defined with a parent's prefix"
+ end
+
+ def test_mounting_at_root_path
+ get "/omg"
+ assert_equal " -- /omg", response.body
end
def test_mounting_sets_script_name
diff --git a/actionpack/test/dispatch/prefix_generation_test.rb b/actionpack/test/dispatch/prefix_generation_test.rb
index e519fff51e..cd31e8e326 100644
--- a/actionpack/test/dispatch/prefix_generation_test.rb
+++ b/actionpack/test/dispatch/prefix_generation_test.rb
@@ -15,6 +15,9 @@ module TestGenerationPrefix
ActiveModel::Name.new(klass)
end
+
+ def to_model; self; end
+ def persisted?; true; end
end
class WithMountedEngine < ActionDispatch::IntegrationTest
@@ -32,12 +35,18 @@ module TestGenerationPrefix
get "/conflicting_url", :to => "inside_engine_generating#conflicting"
get "/foo", :to => "never#invoked", :as => :named_helper_that_should_be_invoked_only_in_respond_to_test
- get "/relative_path_redirect", :to => redirect("foo")
+ get "/relative_path_root", :to => redirect("")
+ get "/relative_path_redirect", :to => redirect("foo")
+ get "/relative_option_root", :to => redirect(:path => "")
get "/relative_option_redirect", :to => redirect(:path => "foo")
+ get "/relative_custom_root", :to => redirect { |params, request| "" }
get "/relative_custom_redirect", :to => redirect { |params, request| "foo" }
- get "/absolute_path_redirect", :to => redirect("/foo")
+ get "/absolute_path_root", :to => redirect("/")
+ get "/absolute_path_redirect", :to => redirect("/foo")
+ get "/absolute_option_root", :to => redirect(:path => "/")
get "/absolute_option_redirect", :to => redirect(:path => "/foo")
+ get "/absolute_custom_root", :to => redirect { |params, request| "/" }
get "/absolute_custom_redirect", :to => redirect { |params, request| "/foo" }
end
@@ -190,46 +199,64 @@ module TestGenerationPrefix
assert_equal "engine", last_response.body
end
+ test "[ENGINE] relative path root uses SCRIPT_NAME from request" do
+ get "/awesome/blog/relative_path_root"
+ verify_redirect "http://example.org/awesome/blog"
+ end
+
test "[ENGINE] relative path redirect uses SCRIPT_NAME from request" do
get "/awesome/blog/relative_path_redirect"
- assert_equal 301, last_response.status
- assert_equal "http://example.org/awesome/blog/foo", last_response.headers["Location"]
- assert_equal %(<html><body>You are being <a href="http://example.org/awesome/blog/foo">redirected</a>.</body></html>), last_response.body
+ verify_redirect "http://example.org/awesome/blog/foo"
+ end
+
+ test "[ENGINE] relative option root uses SCRIPT_NAME from request" do
+ get "/awesome/blog/relative_option_root"
+ verify_redirect "http://example.org/awesome/blog"
end
test "[ENGINE] relative option redirect uses SCRIPT_NAME from request" do
get "/awesome/blog/relative_option_redirect"
- assert_equal 301, last_response.status
- assert_equal "http://example.org/awesome/blog/foo", last_response.headers["Location"]
- assert_equal %(<html><body>You are being <a href="http://example.org/awesome/blog/foo">redirected</a>.</body></html>), last_response.body
+ verify_redirect "http://example.org/awesome/blog/foo"
+ end
+
+ test "[ENGINE] relative custom root uses SCRIPT_NAME from request" do
+ get "/awesome/blog/relative_custom_root"
+ verify_redirect "http://example.org/awesome/blog"
end
test "[ENGINE] relative custom redirect uses SCRIPT_NAME from request" do
get "/awesome/blog/relative_custom_redirect"
- assert_equal 301, last_response.status
- assert_equal "http://example.org/awesome/blog/foo", last_response.headers["Location"]
- assert_equal %(<html><body>You are being <a href="http://example.org/awesome/blog/foo">redirected</a>.</body></html>), last_response.body
+ verify_redirect "http://example.org/awesome/blog/foo"
+ end
+
+ test "[ENGINE] absolute path root doesn't use SCRIPT_NAME from request" do
+ get "/awesome/blog/absolute_path_root"
+ verify_redirect "http://example.org/"
end
test "[ENGINE] absolute path redirect doesn't use SCRIPT_NAME from request" do
get "/awesome/blog/absolute_path_redirect"
- assert_equal 301, last_response.status
- assert_equal "http://example.org/foo", last_response.headers["Location"]
- assert_equal %(<html><body>You are being <a href="http://example.org/foo">redirected</a>.</body></html>), last_response.body
+ verify_redirect "http://example.org/foo"
+ end
+
+ test "[ENGINE] absolute option root doesn't use SCRIPT_NAME from request" do
+ get "/awesome/blog/absolute_option_root"
+ verify_redirect "http://example.org/"
end
test "[ENGINE] absolute option redirect doesn't use SCRIPT_NAME from request" do
get "/awesome/blog/absolute_option_redirect"
- assert_equal 301, last_response.status
- assert_equal "http://example.org/foo", last_response.headers["Location"]
- assert_equal %(<html><body>You are being <a href="http://example.org/foo">redirected</a>.</body></html>), last_response.body
+ verify_redirect "http://example.org/foo"
+ end
+
+ test "[ENGINE] absolute custom root doesn't use SCRIPT_NAME from request" do
+ get "/awesome/blog/absolute_custom_root"
+ verify_redirect "http://example.org/"
end
test "[ENGINE] absolute custom redirect doesn't use SCRIPT_NAME from request" do
get "/awesome/blog/absolute_custom_redirect"
- assert_equal 301, last_response.status
- assert_equal "http://example.org/foo", last_response.headers["Location"]
- assert_equal %(<html><body>You are being <a href="http://example.org/foo">redirected</a>.</body></html>), last_response.body
+ verify_redirect "http://example.org/foo"
end
# Inside Application
@@ -320,6 +347,17 @@ module TestGenerationPrefix
path = engine_object.polymorphic_url(Post.new, :host => "www.example.com")
assert_equal "http://www.example.com/awesome/blog/posts/1", path
end
+
+ private
+ def verify_redirect(url, status = 301)
+ assert_equal status, last_response.status
+ assert_equal url, last_response.headers["Location"]
+ assert_equal expected_redirect_body(url), last_response.body
+ end
+
+ def expected_redirect_body(url)
+ %(<html><body>You are being <a href="#{url}">redirected</a>.</body></html>)
+ end
end
class EngineMountedAtRoot < ActionDispatch::IntegrationTest
@@ -332,12 +370,18 @@ module TestGenerationPrefix
routes.draw do
get "/posts/:id", :to => "posts#show", :as => :post
- get "/relative_path_redirect", :to => redirect("foo")
+ get "/relative_path_root", :to => redirect("")
+ get "/relative_path_redirect", :to => redirect("foo")
+ get "/relative_option_root", :to => redirect(:path => "")
get "/relative_option_redirect", :to => redirect(:path => "foo")
+ get "/relative_custom_root", :to => redirect { |params, request| "" }
get "/relative_custom_redirect", :to => redirect { |params, request| "foo" }
- get "/absolute_path_redirect", :to => redirect("/foo")
+ get "/absolute_path_root", :to => redirect("/")
+ get "/absolute_path_redirect", :to => redirect("/foo")
+ get "/absolute_option_root", :to => redirect(:path => "/")
get "/absolute_option_redirect", :to => redirect(:path => "/foo")
+ get "/absolute_custom_root", :to => redirect { |params, request| "/" }
get "/absolute_custom_redirect", :to => redirect { |params, request| "/foo" }
end
@@ -390,46 +434,75 @@ module TestGenerationPrefix
assert_equal "/posts/1", last_response.body
end
+ test "[ENGINE] relative path root uses SCRIPT_NAME from request" do
+ get "/relative_path_root"
+ verify_redirect "http://example.org/"
+ end
+
test "[ENGINE] relative path redirect uses SCRIPT_NAME from request" do
get "/relative_path_redirect"
- assert_equal 301, last_response.status
- assert_equal "http://example.org/foo", last_response.headers["Location"]
- assert_equal %(<html><body>You are being <a href="http://example.org/foo">redirected</a>.</body></html>), last_response.body
+ verify_redirect "http://example.org/foo"
+ end
+
+ test "[ENGINE] relative option root uses SCRIPT_NAME from request" do
+ get "/relative_option_root"
+ verify_redirect "http://example.org/"
end
test "[ENGINE] relative option redirect uses SCRIPT_NAME from request" do
get "/relative_option_redirect"
- assert_equal 301, last_response.status
- assert_equal "http://example.org/foo", last_response.headers["Location"]
- assert_equal %(<html><body>You are being <a href="http://example.org/foo">redirected</a>.</body></html>), last_response.body
+ verify_redirect "http://example.org/foo"
+ end
+
+ test "[ENGINE] relative custom root uses SCRIPT_NAME from request" do
+ get "/relative_custom_root"
+ verify_redirect "http://example.org/"
end
test "[ENGINE] relative custom redirect uses SCRIPT_NAME from request" do
get "/relative_custom_redirect"
- assert_equal 301, last_response.status
- assert_equal "http://example.org/foo", last_response.headers["Location"]
- assert_equal %(<html><body>You are being <a href="http://example.org/foo">redirected</a>.</body></html>), last_response.body
+ verify_redirect "http://example.org/foo"
+ end
+
+ test "[ENGINE] absolute path root doesn't use SCRIPT_NAME from request" do
+ get "/absolute_path_root"
+ verify_redirect "http://example.org/"
end
test "[ENGINE] absolute path redirect doesn't use SCRIPT_NAME from request" do
get "/absolute_path_redirect"
- assert_equal 301, last_response.status
- assert_equal "http://example.org/foo", last_response.headers["Location"]
- assert_equal %(<html><body>You are being <a href="http://example.org/foo">redirected</a>.</body></html>), last_response.body
+ verify_redirect "http://example.org/foo"
+ end
+
+ test "[ENGINE] absolute option root doesn't use SCRIPT_NAME from request" do
+ get "/absolute_option_root"
+ verify_redirect "http://example.org/"
end
test "[ENGINE] absolute option redirect doesn't use SCRIPT_NAME from request" do
get "/absolute_option_redirect"
- assert_equal 301, last_response.status
- assert_equal "http://example.org/foo", last_response.headers["Location"]
- assert_equal %(<html><body>You are being <a href="http://example.org/foo">redirected</a>.</body></html>), last_response.body
+ verify_redirect "http://example.org/foo"
+ end
+
+ test "[ENGINE] absolute custom root doesn't use SCRIPT_NAME from request" do
+ get "/absolute_custom_root"
+ verify_redirect "http://example.org/"
end
test "[ENGINE] absolute custom redirect doesn't use SCRIPT_NAME from request" do
get "/absolute_custom_redirect"
- assert_equal 301, last_response.status
- assert_equal "http://example.org/foo", last_response.headers["Location"]
- assert_equal %(<html><body>You are being <a href="http://example.org/foo">redirected</a>.</body></html>), last_response.body
- end
+ verify_redirect "http://example.org/foo"
+ end
+
+ private
+ def verify_redirect(url, status = 301)
+ assert_equal status, last_response.status
+ assert_equal url, last_response.headers["Location"]
+ assert_equal expected_redirect_body(url), last_response.body
+ end
+
+ def expected_redirect_body(url)
+ %(<html><body>You are being <a href="#{url}">redirected</a>.</body></html>)
+ end
end
end
diff --git a/actionpack/test/dispatch/rack_test.rb b/actionpack/test/dispatch/rack_test.rb
deleted file mode 100644
index 42067854ee..0000000000
--- a/actionpack/test/dispatch/rack_test.rb
+++ /dev/null
@@ -1,191 +0,0 @@
-require 'abstract_unit'
-
-# TODO: Merge these tests into RequestTest
-
-class BaseRackTest < ActiveSupport::TestCase
- def setup
- @env = {
- "HTTP_MAX_FORWARDS" => "10",
- "SERVER_NAME" => "glu.ttono.us",
- "FCGI_ROLE" => "RESPONDER",
- "AUTH_TYPE" => "Basic",
- "HTTP_X_FORWARDED_HOST" => "glu.ttono.us",
- "HTTP_ACCEPT_CHARSET" => "UTF-8",
- "HTTP_ACCEPT_ENCODING" => "gzip, deflate",
- "HTTP_CACHE_CONTROL" => "no-cache, max-age=0",
- "HTTP_PRAGMA" => "no-cache",
- "HTTP_USER_AGENT" => "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)",
- "PATH_INFO" => "/homepage/",
- "HTTP_ACCEPT_LANGUAGE" => "en",
- "HTTP_NEGOTIATE" => "trans",
- "HTTP_HOST" => "glu.ttono.us:8007",
- "HTTP_REFERER" => "http://www.google.com/search?q=glu.ttono.us",
- "HTTP_FROM" => "googlebot",
- "SERVER_PROTOCOL" => "HTTP/1.1",
- "REDIRECT_URI" => "/dispatch.fcgi",
- "SCRIPT_NAME" => "/dispatch.fcgi",
- "SERVER_ADDR" => "207.7.108.53",
- "REMOTE_ADDR" => "207.7.108.53",
- "REMOTE_HOST" => "google.com",
- "REMOTE_IDENT" => "kevin",
- "REMOTE_USER" => "kevin",
- "SERVER_SOFTWARE" => "lighttpd/1.4.5",
- "HTTP_COOKIE" => "_session_id=c84ace84796670c052c6ceb2451fb0f2; is_admin=yes",
- "HTTP_X_FORWARDED_SERVER" => "glu.ttono.us",
- "REQUEST_URI" => "/admin",
- "DOCUMENT_ROOT" => "/home/kevinc/sites/typo/public",
- "PATH_TRANSLATED" => "/home/kevinc/sites/typo/public/homepage/",
- "SERVER_PORT" => "8007",
- "QUERY_STRING" => "",
- "REMOTE_PORT" => "63137",
- "GATEWAY_INTERFACE" => "CGI/1.1",
- "HTTP_X_FORWARDED_FOR" => "65.88.180.234",
- "HTTP_ACCEPT" => "*/*",
- "SCRIPT_FILENAME" => "/home/kevinc/sites/typo/public/dispatch.fcgi",
- "REDIRECT_STATUS" => "200",
- "REQUEST_METHOD" => "GET"
- }
- @request = ActionDispatch::Request.new(@env)
- # some Nokia phone browsers omit the space after the semicolon separator.
- # some developers have grown accustomed to using comma in cookie values.
- @alt_cookie_fmt_request = ActionDispatch::Request.new(@env.merge({"HTTP_COOKIE"=>"_session_id=c84ace847,96670c052c6ceb2451fb0f2;is_admin=yes"}))
- end
-
- private
- def set_content_data(data)
- @request.env['REQUEST_METHOD'] = 'POST'
- @request.env['CONTENT_LENGTH'] = data.length
- @request.env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=utf-8'
- @request.env['rack.input'] = StringIO.new(data)
- end
-end
-
-class RackRequestTest < BaseRackTest
- test "proxy request" do
- assert_equal 'glu.ttono.us', @request.host_with_port
- end
-
- test "http host" do
- @env.delete "HTTP_X_FORWARDED_HOST"
- @env['HTTP_HOST'] = "rubyonrails.org:8080"
- assert_equal "rubyonrails.org", @request.host
- assert_equal "rubyonrails.org:8080", @request.host_with_port
-
- @env['HTTP_X_FORWARDED_HOST'] = "www.firsthost.org, www.secondhost.org"
- assert_equal "www.secondhost.org", @request.host
- end
-
- test "http host with default port overrides server port" do
- @env.delete "HTTP_X_FORWARDED_HOST"
- @env['HTTP_HOST'] = "rubyonrails.org"
- assert_equal "rubyonrails.org", @request.host_with_port
- end
-
- test "host with port defaults to server name if no host headers" do
- @env.delete "HTTP_X_FORWARDED_HOST"
- @env.delete "HTTP_HOST"
- assert_equal "glu.ttono.us:8007", @request.host_with_port
- end
-
- test "host with port falls back to server addr if necessary" do
- @env.delete "HTTP_X_FORWARDED_HOST"
- @env.delete "HTTP_HOST"
- @env.delete "SERVER_NAME"
- assert_equal "207.7.108.53", @request.host
- assert_equal 8007, @request.port
- assert_equal "207.7.108.53:8007", @request.host_with_port
- end
-
- test "host with port if http standard port is specified" do
- @env['HTTP_X_FORWARDED_HOST'] = "glu.ttono.us:80"
- assert_equal "glu.ttono.us", @request.host_with_port
- end
-
- test "host with port if https standard port is specified" do
- @env['HTTP_X_FORWARDED_PROTO'] = "https"
- @env['HTTP_X_FORWARDED_HOST'] = "glu.ttono.us:443"
- assert_equal "glu.ttono.us", @request.host_with_port
- end
-
- test "host if ipv6 reference" do
- @env.delete "HTTP_X_FORWARDED_HOST"
- @env['HTTP_HOST'] = "[2001:1234:5678:9abc:def0::dead:beef]"
- assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", @request.host
- end
-
- test "host if ipv6 reference with port" do
- @env.delete "HTTP_X_FORWARDED_HOST"
- @env['HTTP_HOST'] = "[2001:1234:5678:9abc:def0::dead:beef]:8008"
- assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", @request.host
- end
-
- test "cgi environment variables" do
- assert_equal "Basic", @request.auth_type
- assert_equal 0, @request.content_length
- assert_equal nil, @request.content_mime_type
- assert_equal "CGI/1.1", @request.gateway_interface
- assert_equal "*/*", @request.accept
- assert_equal "UTF-8", @request.accept_charset
- assert_equal "gzip, deflate", @request.accept_encoding
- assert_equal "en", @request.accept_language
- assert_equal "no-cache, max-age=0", @request.cache_control
- assert_equal "googlebot", @request.from
- assert_equal "glu.ttono.us", @request.host
- assert_equal "trans", @request.negotiate
- assert_equal "no-cache", @request.pragma
- assert_equal "http://www.google.com/search?q=glu.ttono.us", @request.referer
- assert_equal "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)", @request.user_agent
- assert_equal "/homepage/", @request.path_info
- assert_equal "/home/kevinc/sites/typo/public/homepage/", @request.path_translated
- assert_equal "", @request.query_string
- assert_equal "207.7.108.53", @request.remote_addr
- assert_equal "google.com", @request.remote_host
- assert_equal "kevin", @request.remote_ident
- assert_equal "kevin", @request.remote_user
- assert_equal "GET", @request.request_method
- assert_equal "/dispatch.fcgi", @request.script_name
- assert_equal "glu.ttono.us", @request.server_name
- assert_equal 8007, @request.server_port
- assert_equal "HTTP/1.1", @request.server_protocol
- assert_equal "lighttpd", @request.server_software
- end
-
- test "cookie syntax resilience" do
- cookies = @request.cookies
- assert_equal "c84ace84796670c052c6ceb2451fb0f2", cookies["_session_id"], cookies.inspect
- assert_equal "yes", cookies["is_admin"], cookies.inspect
-
- alt_cookies = @alt_cookie_fmt_request.cookies
- #assert_equal "c84ace847,96670c052c6ceb2451fb0f2", alt_cookies["_session_id"], alt_cookies.inspect
- assert_equal "yes", alt_cookies["is_admin"], alt_cookies.inspect
- end
-end
-
-class RackRequestParamsParsingTest < BaseRackTest
- test "doesnt break when content type has charset" do
- set_content_data 'flamenco=love'
-
- assert_equal({"flamenco"=> "love"}, @request.request_parameters)
- end
-
- test "doesnt interpret request uri as query string when missing" do
- @request.env['REQUEST_URI'] = 'foo'
- assert_equal({}, @request.query_parameters)
- end
-end
-
-class RackRequestNeedsRewoundTest < BaseRackTest
- test "body should be rewound" do
- data = 'foo'
- @env['rack.input'] = StringIO.new(data)
- @env['CONTENT_LENGTH'] = data.length
- @env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=utf-8'
-
- # Read the request body by parsing params.
- request = ActionDispatch::Request.new(@env)
- request.request_parameters
-
- # Should have rewound the body.
- assert_equal 0, request.body.pos
- end
-end
diff --git a/actionpack/test/dispatch/reloader_test.rb b/actionpack/test/dispatch/reloader_test.rb
index ce9ccfcee8..62e8197e20 100644
--- a/actionpack/test/dispatch/reloader_test.rb
+++ b/actionpack/test/dispatch/reloader_test.rb
@@ -3,6 +3,11 @@ require 'abstract_unit'
class ReloaderTest < ActiveSupport::TestCase
Reloader = ActionDispatch::Reloader
+ teardown do
+ Reloader.reset_callbacks :prepare
+ Reloader.reset_callbacks :cleanup
+ end
+
def test_prepare_callbacks
a = b = c = nil
Reloader.to_prepare { |*args| a = b = c = 1 }
diff --git a/actionpack/test/dispatch/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb
index dba9ab688f..c609075e6b 100644
--- a/actionpack/test/dispatch/request/json_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb
@@ -23,6 +23,13 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest
)
end
+ test "parses boolean and number json params for application json" do
+ assert_parses(
+ {"item" => {"enabled" => false, "count" => 10}},
+ "{\"item\": {\"enabled\": false, \"count\": 10}}", { 'CONTENT_TYPE' => 'application/json' }
+ )
+ end
+
test "parses json params for application jsonrequest" do
assert_parses(
{"person" => {"name" => "David"}},
diff --git a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb
index 2a2f92b5b3..2db3fee6bb 100644
--- a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb
@@ -145,7 +145,7 @@ class MultipartParamsParsingTest < ActionDispatch::IntegrationTest
test "does not raise EOFError on GET request with multipart content-type" do
with_routing do |set|
set.draw do
- get ':action', to: 'multipart_params_parsing_test/test'
+ get ':action', controller: 'multipart_params_parsing_test/test'
end
headers = { "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x" }
get "/parse", {}, headers
@@ -174,7 +174,7 @@ class MultipartParamsParsingTest < ActionDispatch::IntegrationTest
def with_test_routing
with_routing do |set|
set.draw do
- post ':action', :to => 'multipart_params_parsing_test/test'
+ post ':action', :controller => 'multipart_params_parsing_test/test'
end
yield
end
diff --git a/actionpack/test/dispatch/request/query_string_parsing_test.rb b/actionpack/test/dispatch/request/query_string_parsing_test.rb
index f072a9f717..4e99c26e03 100644
--- a/actionpack/test/dispatch/request/query_string_parsing_test.rb
+++ b/actionpack/test/dispatch/request/query_string_parsing_test.rb
@@ -11,6 +11,17 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest
head :ok
end
end
+ class EarlyParse
+ def initialize(app)
+ @app = app
+ end
+
+ def call(env)
+ # Trigger a Rack parse so that env caches the query params
+ Rack::Request.new(env).params
+ @app.call(env)
+ end
+ end
def teardown
TestController.last_query_parameters = nil
@@ -93,6 +104,22 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest
assert_parses({"action" => ['1']}, "action[]=1&action[]")
end
+ test "perform_deep_munge" do
+ old_perform_deep_munge = ActionDispatch::Request::Utils.perform_deep_munge
+ ActionDispatch::Request::Utils.perform_deep_munge = false
+ begin
+ assert_parses({"action" => nil}, "action")
+ assert_parses({"action" => {"foo" => nil}}, "action[foo]")
+ assert_parses({"action" => {"foo" => {"bar" => nil}}}, "action[foo][bar]")
+ assert_parses({"action" => {"foo" => {"bar" => [nil]}}}, "action[foo][bar][]")
+ assert_parses({"action" => {"foo" => [nil]}}, "action[foo][]")
+ assert_parses({"action" => {"foo" => [{"bar" => nil}]}}, "action[foo][][bar]")
+ assert_parses({"action" => ['1',nil]}, "action[]=1&action[]")
+ ensure
+ ActionDispatch::Request::Utils.perform_deep_munge = old_perform_deep_munge
+ end
+ end
+
test "query string with empty key" do
assert_parses(
{ "action" => "create_customer", "full_name" => "David Heinemeier Hansson" },
@@ -131,6 +158,10 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest
set.draw do
get ':action', :to => ::QueryStringParsingTest::TestController
end
+ @app = self.class.build_app(set) do |middleware|
+ middleware.use(EarlyParse)
+ end
+
get "/parse", actual
assert_response :ok
diff --git a/actionpack/test/dispatch/request/session_test.rb b/actionpack/test/dispatch/request/session_test.rb
index 1517f96fdc..10fb04e230 100644
--- a/actionpack/test/dispatch/request/session_test.rb
+++ b/actionpack/test/dispatch/request/session_test.rb
@@ -36,29 +36,71 @@ module ActionDispatch
assert_equal s, Session.find(env)
end
+ def test_destroy
+ s = Session.create(store, {}, {})
+ s['rails'] = 'ftw'
+
+ s.destroy
+
+ assert_empty s
+ end
+
def test_keys
- env = {}
- s = Session.create(store, env, {})
+ s = Session.create(store, {}, {})
s['rails'] = 'ftw'
s['adequate'] = 'awesome'
assert_equal %w[rails adequate], s.keys
end
def test_values
- env = {}
- s = Session.create(store, env, {})
+ s = Session.create(store, {}, {})
s['rails'] = 'ftw'
s['adequate'] = 'awesome'
assert_equal %w[ftw awesome], s.values
end
def test_clear
- env = {}
- s = Session.create(store, env, {})
+ s = Session.create(store, {}, {})
s['rails'] = 'ftw'
s['adequate'] = 'awesome'
+
s.clear
- assert_equal([], s.values)
+ assert_empty(s.values)
+ end
+
+ def test_update
+ s = Session.create(store, {}, {})
+ s['rails'] = 'ftw'
+
+ s.update(:rails => 'awesome')
+
+ assert_equal(['rails'], s.keys)
+ assert_equal('awesome', s['rails'])
+ end
+
+ def test_delete
+ s = Session.create(store, {}, {})
+ s['rails'] = 'ftw'
+
+ s.delete('rails')
+
+ assert_empty(s.keys)
+ end
+
+ def test_fetch
+ session = Session.create(store, {}, {})
+
+ session['one'] = '1'
+ assert_equal '1', session.fetch(:one)
+
+ assert_equal '2', session.fetch(:two, '2')
+ assert_nil session.fetch(:two, nil)
+
+ assert_equal 'three', session.fetch(:three) {|el| el.to_s }
+
+ assert_raise KeyError do
+ session.fetch(:three)
+ end
end
private
@@ -66,6 +108,7 @@ module ActionDispatch
Class.new {
def load_session(env); [1, {}]; end
def session_exists?(env); true; end
+ def destroy_session(env, id, options); 123; end
}.new
end
end
diff --git a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb
index 9a77454f30..1de05cbf09 100644
--- a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb
@@ -130,10 +130,7 @@ class UrlEncodedParamsParsingTest < ActionDispatch::IntegrationTest
end
test "ambiguous params returns a bad request" do
- with_routing do |set|
- set.draw do
- post ':action', to: ::UrlEncodedParamsParsingTest::TestController
- end
+ with_test_routing do
post "/parse", "foo[]=bar&foo[4]=bar"
assert_response :bad_request
end
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index f6de9748ca..e4950a5d6b 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -1,12 +1,34 @@
require 'abstract_unit'
-class RequestTest < ActiveSupport::TestCase
+class BaseRequestTest < ActiveSupport::TestCase
+ def setup
+ @env = {
+ :ip_spoofing_check => true,
+ :tld_length => 1,
+ "rack.input" => "foo"
+ }
+ end
def url_for(options = {})
options = { host: 'www.example.com' }.merge!(options)
ActionDispatch::Http::URL.url_for(options)
end
+ protected
+ def stub_request(env = {})
+ ip_spoofing_check = env.key?(:ip_spoofing_check) ? env.delete(:ip_spoofing_check) : true
+ @trusted_proxies ||= nil
+ ip_app = ActionDispatch::RemoteIp.new(Proc.new { }, ip_spoofing_check, @trusted_proxies)
+ tld_length = env.key?(:tld_length) ? env.delete(:tld_length) : 1
+ ip_app.call(env)
+ ActionDispatch::Http::URL.tld_length = tld_length
+
+ env = @env.merge(env)
+ ActionDispatch::Request.new(env)
+ end
+end
+
+class RequestUrlFor < BaseRequestTest
test "url_for class method" do
e = assert_raise(ArgumentError) { url_for(:host => nil) }
assert_match(/Please provide the :host parameter/, e.message)
@@ -31,7 +53,9 @@ class RequestTest < ActiveSupport::TestCase
assert_equal 'http://www.example.com?params=', url_for(:params => '')
assert_equal 'http://www.example.com?params=1', url_for(:params => 1)
end
+end
+class RequestIP < BaseRequestTest
test "remote ip" do
request = stub_request 'REMOTE_ADDR' => '1.2.3.4'
assert_equal '1.2.3.4', request.remote_ip
@@ -93,6 +117,14 @@ class RequestTest < ActiveSupport::TestCase
assert_equal '1.1.1.1', request.remote_ip
end
+ test "remote ip spoof protection ignores private addresses" do
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => '172.17.19.51',
+ 'HTTP_CLIENT_IP' => '172.17.19.51',
+ 'REMOTE_ADDR' => '1.1.1.1',
+ 'HTTP_X_BLUECOAT_VIA' => 'de462e07a2db325e'
+ assert_equal '1.1.1.1', request.remote_ip
+ end
+
test "remote ip v6" do
request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334'
assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip
@@ -120,9 +152,12 @@ class RequestTest < ActiveSupport::TestCase
request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,::1'
assert_equal nil, request.remote_ip
- request = stub_request 'HTTP_X_FORWARDED_FOR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334, fe80:0000:0000:0000:0202:b3ff:fe1e:8329, ::1, fc00::'
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334, fe80:0000:0000:0000:0202:b3ff:fe1e:8329, ::1, fc00::, fc01::, fdff'
assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => 'FE00::, FDFF::'
+ assert_equal 'FE00::', request.remote_ip
+
request = stub_request 'HTTP_X_FORWARDED_FOR' => 'not_ip_address'
assert_equal nil, request.remote_ip
end
@@ -212,10 +247,12 @@ class RequestTest < ActiveSupport::TestCase
end
test "remote ip middleware not present still returns an IP" do
- request = ActionDispatch::Request.new({'REMOTE_ADDR' => '127.0.0.1'})
+ request = stub_request('REMOTE_ADDR' => '127.0.0.1')
assert_equal '127.0.0.1', request.remote_ip
end
+end
+class RequestDomain < BaseRequestTest
test "domains" do
request = stub_request 'HTTP_HOST' => 'www.rubyonrails.org'
assert_equal "rubyonrails.org", request.domain
@@ -273,7 +310,9 @@ class RequestTest < ActiveSupport::TestCase
assert_equal [], request.subdomains
assert_equal "", request.subdomain
end
+end
+class RequestPort < BaseRequestTest
test "standard_port" do
request = stub_request
assert_equal 80, request.standard_port
@@ -315,7 +354,9 @@ class RequestTest < ActiveSupport::TestCase
request = stub_request 'HTTP_HOST' => 'www.example.org:8080'
assert_equal ':8080', request.port_string
end
+end
+class RequestPath < BaseRequestTest
test "full path" do
request = stub_request 'SCRIPT_NAME' => '', 'PATH_INFO' => '/path/of/some/uri', 'QUERY_STRING' => 'mapped=1'
assert_equal "/path/of/some/uri?mapped=1", request.fullpath
@@ -346,6 +387,32 @@ class RequestTest < ActiveSupport::TestCase
assert_equal "/of/some/uri", request.path_info
end
+ test "original_fullpath returns ORIGINAL_FULLPATH" do
+ request = stub_request('ORIGINAL_FULLPATH' => "/foo?bar")
+
+ path = request.original_fullpath
+ assert_equal "/foo?bar", path
+ end
+
+ test "original_url returns url built using ORIGINAL_FULLPATH" do
+ request = stub_request('ORIGINAL_FULLPATH' => "/foo?bar",
+ 'HTTP_HOST' => "example.org",
+ 'rack.url_scheme' => "http")
+
+ url = request.original_url
+ assert_equal "http://example.org/foo?bar", url
+ end
+
+ test "original_fullpath returns fullpath if ORIGINAL_FULLPATH is not present" do
+ request = stub_request('PATH_INFO' => "/foo",
+ 'QUERY_STRING' => "bar")
+
+ path = request.original_fullpath
+ assert_equal "/foo?bar", path
+ end
+end
+
+class RequestHost < BaseRequestTest
test "host with default port" do
request = stub_request 'HTTP_HOST' => 'rubyonrails.org:80'
assert_equal "rubyonrails.org", request.host_with_port
@@ -356,15 +423,174 @@ class RequestTest < ActiveSupport::TestCase
assert_equal "rubyonrails.org:81", request.host_with_port
end
- test "server software" do
- request = stub_request
- assert_equal nil, request.server_software
+ test "proxy request" do
+ request = stub_request 'HTTP_HOST' => 'glu.ttono.us:80'
+ assert_equal "glu.ttono.us", request.host_with_port
+ end
+
+ test "http host" do
+ request = stub_request 'HTTP_HOST' => "rubyonrails.org:8080"
+ assert_equal "rubyonrails.org", request.host
+ assert_equal "rubyonrails.org:8080", request.host_with_port
+
+ request = stub_request 'HTTP_X_FORWARDED_HOST' => "www.firsthost.org, www.secondhost.org"
+ assert_equal "www.secondhost.org", request.host
+ end
+
+ test "http host with default port overrides server port" do
+ request = stub_request 'HTTP_HOST' => "rubyonrails.org"
+ assert_equal "rubyonrails.org", request.host_with_port
+ end
+
+ test "host with port if http standard port is specified" do
+ request = stub_request 'HTTP_X_FORWARDED_HOST' => "glu.ttono.us:80"
+ assert_equal "glu.ttono.us", request.host_with_port
+ end
+
+ test "host with port if https standard port is specified" do
+ request = stub_request(
+ 'HTTP_X_FORWARDED_PROTO' => "https",
+ 'HTTP_X_FORWARDED_HOST' => "glu.ttono.us:443"
+ )
+ assert_equal "glu.ttono.us", request.host_with_port
+ end
+
+ test "host if ipv6 reference" do
+ request = stub_request 'HTTP_HOST' => "[2001:1234:5678:9abc:def0::dead:beef]"
+ assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", request.host
+ end
+
+ test "host if ipv6 reference with port" do
+ request = stub_request 'HTTP_HOST' => "[2001:1234:5678:9abc:def0::dead:beef]:8008"
+ assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", request.host
+ end
+end
+
+class RequestCGI < BaseRequestTest
+ test "CGI environment variables" do
+ request = stub_request(
+ "AUTH_TYPE" => "Basic",
+ "GATEWAY_INTERFACE" => "CGI/1.1",
+ "HTTP_ACCEPT" => "*/*",
+ "HTTP_ACCEPT_CHARSET" => "UTF-8",
+ "HTTP_ACCEPT_ENCODING" => "gzip, deflate",
+ "HTTP_ACCEPT_LANGUAGE" => "en",
+ "HTTP_CACHE_CONTROL" => "no-cache, max-age=0",
+ "HTTP_FROM" => "googlebot",
+ "HTTP_HOST" => "glu.ttono.us:8007",
+ "HTTP_NEGOTIATE" => "trans",
+ "HTTP_PRAGMA" => "no-cache",
+ "HTTP_REFERER" => "http://www.google.com/search?q=glu.ttono.us",
+ "HTTP_USER_AGENT" => "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)",
+ "PATH_INFO" => "/homepage/",
+ "PATH_TRANSLATED" => "/home/kevinc/sites/typo/public/homepage/",
+ "QUERY_STRING" => "",
+ "REMOTE_ADDR" => "207.7.108.53",
+ "REMOTE_HOST" => "google.com",
+ "REMOTE_IDENT" => "kevin",
+ "REMOTE_USER" => "kevin",
+ "REQUEST_METHOD" => "GET",
+ "SCRIPT_NAME" => "/dispatch.fcgi",
+ "SERVER_NAME" => "glu.ttono.us",
+ "SERVER_PORT" => "8007",
+ "SERVER_PROTOCOL" => "HTTP/1.1",
+ "SERVER_SOFTWARE" => "lighttpd/1.4.5",
+ )
+
+ assert_equal "Basic", request.auth_type
+ assert_equal 0, request.content_length
+ assert_equal nil, request.content_mime_type
+ assert_equal "CGI/1.1", request.gateway_interface
+ assert_equal "*/*", request.accept
+ assert_equal "UTF-8", request.accept_charset
+ assert_equal "gzip, deflate", request.accept_encoding
+ assert_equal "en", request.accept_language
+ assert_equal "no-cache, max-age=0", request.cache_control
+ assert_equal "googlebot", request.from
+ assert_equal "glu.ttono.us", request.host
+ assert_equal "trans", request.negotiate
+ assert_equal "no-cache", request.pragma
+ assert_equal "http://www.google.com/search?q=glu.ttono.us", request.referer
+ assert_equal "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)", request.user_agent
+ assert_equal "/homepage/", request.path_info
+ assert_equal "/home/kevinc/sites/typo/public/homepage/", request.path_translated
+ assert_equal "", request.query_string
+ assert_equal "207.7.108.53", request.remote_addr
+ assert_equal "google.com", request.remote_host
+ assert_equal "kevin", request.remote_ident
+ assert_equal "kevin", request.remote_user
+ assert_equal "GET", request.request_method
+ assert_equal "/dispatch.fcgi", request.script_name
+ assert_equal "glu.ttono.us", request.server_name
+ assert_equal 8007, request.server_port
+ assert_equal "HTTP/1.1", request.server_protocol
+ assert_equal "lighttpd", request.server_software
+ end
+end
+
+class RequestCookie < BaseRequestTest
+ test "cookie syntax resilience" do
+ request = stub_request("HTTP_COOKIE" => "_session_id=c84ace84796670c052c6ceb2451fb0f2; is_admin=yes")
+ assert_equal "c84ace84796670c052c6ceb2451fb0f2", request.cookies["_session_id"], request.cookies.inspect
+ assert_equal "yes", request.cookies["is_admin"], request.cookies.inspect
- request = stub_request 'SERVER_SOFTWARE' => 'Apache3.422'
- assert_equal 'apache', request.server_software
+ # some Nokia phone browsers omit the space after the semicolon separator.
+ # some developers have grown accustomed to using comma in cookie values.
+ request = stub_request("HTTP_COOKIE"=>"_session_id=c84ace847,96670c052c6ceb2451fb0f2;is_admin=yes")
+ assert_equal "c84ace847", request.cookies["_session_id"], request.cookies.inspect
+ assert_equal "yes", request.cookies["is_admin"], request.cookies.inspect
+ end
+end
+
+class RequestParamsParsing < BaseRequestTest
+ test "doesnt break when content type has charset" do
+ request = stub_request(
+ 'REQUEST_METHOD' => 'POST',
+ 'CONTENT_LENGTH' => "flamenco=love".length,
+ 'CONTENT_TYPE' => 'application/x-www-form-urlencoded; charset=utf-8',
+ 'rack.input' => StringIO.new("flamenco=love")
+ )
+
+ assert_equal({"flamenco"=> "love"}, request.request_parameters)
+ end
+
+ test "doesnt interpret request uri as query string when missing" do
+ request = stub_request('REQUEST_URI' => 'foo')
+ assert_equal({}, request.query_parameters)
+ end
+end
- request = stub_request 'SERVER_SOFTWARE' => 'lighttpd(1.1.4)'
- assert_equal 'lighttpd', request.server_software
+class RequestRewind < BaseRequestTest
+ test "body should be rewound" do
+ data = 'rewind'
+ env = {
+ 'rack.input' => StringIO.new(data),
+ 'CONTENT_LENGTH' => data.length,
+ 'CONTENT_TYPE' => 'application/x-www-form-urlencoded; charset=utf-8'
+ }
+
+ # Read the request body by parsing params.
+ request = stub_request(env)
+ request.request_parameters
+
+ # Should have rewound the body.
+ assert_equal 0, request.body.pos
+ end
+
+ test "raw_post rewinds rack.input if RAW_POST_DATA is nil" do
+ request = stub_request(
+ 'rack.input' => StringIO.new("raw"),
+ 'CONTENT_LENGTH' => 3
+ )
+ assert_equal "raw", request.raw_post
+ assert_equal "raw", request.env['rack.input'].read
+ end
+end
+
+class RequestProtocol < BaseRequestTest
+ test "server software" do
+ assert_equal 'lighttpd', stub_request('SERVER_SOFTWARE' => 'lighttpd/1.4.5').server_software
+ assert_equal 'apache', stub_request('SERVER_SOFTWARE' => 'Apache3.422').server_software
end
test "xml http request" do
@@ -383,19 +609,12 @@ class RequestTest < ActiveSupport::TestCase
end
test "reports ssl" do
- request = stub_request
- assert !request.ssl?
-
- request = stub_request 'HTTPS' => 'on'
- assert request.ssl?
+ assert !stub_request.ssl?
+ assert stub_request('HTTPS' => 'on').ssl?
end
test "reports ssl when proxied via lighttpd" do
- request = stub_request
- assert !request.ssl?
-
- request = stub_request 'HTTP_X_FORWARDED_PROTO' => 'https'
- assert request.ssl?
+ assert stub_request('HTTP_X_FORWARDED_PROTO' => 'https').ssl?
end
test "scheme returns https when proxied" do
@@ -403,63 +622,72 @@ class RequestTest < ActiveSupport::TestCase
assert !request.ssl?
assert_equal 'http', request.scheme
- request = stub_request 'rack.url_scheme' => 'http', 'HTTP_X_FORWARDED_PROTO' => 'https'
+ request = stub_request(
+ 'rack.url_scheme' => 'http',
+ 'HTTP_X_FORWARDED_PROTO' => 'https'
+ )
assert request.ssl?
assert_equal 'https', request.scheme
end
+end
- test "String request methods" do
- [:get, :post, :patch, :put, :delete].each do |method|
- request = stub_request 'REQUEST_METHOD' => method.to_s.upcase
- assert_equal method.to_s.upcase, request.method
- end
- end
+class RequestMethod < BaseRequestTest
+ test "request methods" do
+ [:post, :get, :patch, :put, :delete].each do |method|
+ request = stub_request('REQUEST_METHOD' => method.to_s.upcase)
- test "Symbol forms of request methods via method_symbol" do
- [:get, :post, :patch, :put, :delete].each do |method|
- request = stub_request 'REQUEST_METHOD' => method.to_s.upcase
+ assert_equal method.to_s.upcase, request.method
assert_equal method, request.method_symbol
end
end
test "invalid http method raises exception" do
assert_raise(ActionController::UnknownHttpMethod) do
- request = stub_request 'REQUEST_METHOD' => 'RANDOM_METHOD'
- request.request_method
+ stub_request('REQUEST_METHOD' => 'RANDOM_METHOD').request_method
end
end
test "allow method hacking on post" do
%w(GET OPTIONS PATCH PUT POST DELETE).each do |method|
- request = stub_request "REQUEST_METHOD" => method.to_s.upcase
+ request = stub_request 'REQUEST_METHOD' => method.to_s.upcase
+
assert_equal(method == "HEAD" ? "GET" : method, request.method)
end
end
test "invalid method hacking on post raises exception" do
assert_raise(ActionController::UnknownHttpMethod) do
- request = stub_request "REQUEST_METHOD" => "_RANDOM_METHOD"
- request.request_method
+ stub_request('REQUEST_METHOD' => '_RANDOM_METHOD').request_method
end
end
test "restrict method hacking" do
[:get, :patch, :put, :delete].each do |method|
- request = stub_request 'REQUEST_METHOD' => method.to_s.upcase,
- 'action_dispatch.request.request_parameters' => { :_method => 'put' }
+ request = stub_request(
+ 'action_dispatch.request.request_parameters' => { :_method => 'put' },
+ 'REQUEST_METHOD' => method.to_s.upcase
+ )
+
assert_equal method.to_s.upcase, request.method
end
end
test "post masquerading as patch" do
- request = stub_request 'REQUEST_METHOD' => 'PATCH', "rack.methodoverride.original_method" => "POST"
+ request = stub_request(
+ 'REQUEST_METHOD' => 'PATCH',
+ "rack.methodoverride.original_method" => "POST"
+ )
+
assert_equal "POST", request.method
assert_equal "PATCH", request.request_method
assert request.patch?
end
test "post masquerading as put" do
- request = stub_request 'REQUEST_METHOD' => 'PUT', "rack.methodoverride.original_method" => "POST"
+ request = stub_request(
+ 'REQUEST_METHOD' => 'PUT',
+ "rack.methodoverride.original_method" => "POST"
+ )
assert_equal "POST", request.method
assert_equal "PUT", request.request_method
assert request.put?
@@ -485,7 +713,9 @@ class RequestTest < ActiveSupport::TestCase
end
end
end
+end
+class RequestFormat < BaseRequestTest
test "xml format" do
request = stub_request
request.expects(:parameters).at_least_once.returns({ :format => 'xml' })
@@ -505,109 +735,55 @@ class RequestTest < ActiveSupport::TestCase
end
test "XMLHttpRequest" do
- request = stub_request 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest',
- 'HTTP_ACCEPT' =>
- [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(",")
+ request = stub_request(
+ 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest',
+ 'HTTP_ACCEPT' => [Mime::JS, Mime::HTML, Mime::XML, "text/xml", Mime::ALL].join(",")
+ )
request.expects(:parameters).at_least_once.returns({})
assert request.xhr?
assert_equal Mime::JS, request.format
end
- test "content type" do
- request = stub_request 'CONTENT_TYPE' => 'text/html'
- assert_equal Mime::HTML, request.content_mime_type
- end
-
- test "can override format with parameter" do
+ test "can override format with parameter negative" do
request = stub_request
request.expects(:parameters).at_least_once.returns({ :format => :txt })
assert !request.format.xml?
+ end
+ test "can override format with parameter positive" do
request = stub_request
request.expects(:parameters).at_least_once.returns({ :format => :xml })
assert request.format.xml?
end
- test "no content type" do
- request = stub_request
- assert_equal nil, request.content_mime_type
- end
-
- test "content type is XML" do
- request = stub_request 'CONTENT_TYPE' => 'application/xml'
- assert_equal Mime::XML, request.content_mime_type
- end
-
- test "content type with charset" do
- request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8'
- assert_equal Mime::XML, request.content_mime_type
- end
-
- test "user agent" do
- request = stub_request 'HTTP_USER_AGENT' => 'TestAgent'
- assert_equal 'TestAgent', request.user_agent
- end
-
- test "parameters" do
- request = stub_request
- request.stubs(:request_parameters).returns({ "foo" => 1 })
- request.stubs(:query_parameters).returns({ "bar" => 2 })
-
- assert_equal({"foo" => 1, "bar" => 2}, request.parameters)
- assert_equal({"foo" => 1}, request.request_parameters)
- assert_equal({"bar" => 2}, request.query_parameters)
- end
-
- test "parameters still accessible after rack parse error" do
- mock_rack_env = { "QUERY_STRING" => "x[y]=1&x[y][][w]=2", "rack.input" => "foo" }
- request = nil
- request = stub_request(mock_rack_env)
-
- assert_raises(ActionController::BadRequest) do
- # rack will raise a TypeError when parsing this query string
- request.parameters
- end
-
- assert_equal({}, request.parameters)
- end
-
- test "we have access to the original exception" do
- mock_rack_env = { "QUERY_STRING" => "x[y]=1&x[y][][w]=2", "rack.input" => "foo" }
- request = nil
- request = stub_request(mock_rack_env)
-
- e = assert_raises(ActionController::BadRequest) do
- # rack will raise a TypeError when parsing this query string
- request.parameters
- end
-
- assert e.original_exception
- assert_equal e.original_exception.backtrace, e.backtrace
- end
-
- test "formats with accept header" do
+ test "formats text/html with accept header" do
request = stub_request 'HTTP_ACCEPT' => 'text/html'
- request.expects(:parameters).at_least_once.returns({})
assert_equal [Mime::HTML], request.formats
+ end
+ test "formats blank with accept header" do
request = stub_request 'HTTP_ACCEPT' => ''
- request.expects(:parameters).at_least_once.returns({})
assert_equal [Mime::HTML], request.formats
+ end
- request = stub_request 'HTTP_ACCEPT' => '',
- 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
- request.expects(:parameters).at_least_once.returns({})
+ test "formats XMLHttpRequest with accept header" do
+ request = stub_request 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
assert_equal [Mime::JS], request.formats
-
- request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8',
- 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
- request.expects(:parameters).at_least_once.returns({})
+ end
+
+ test "formats application/xml with accept header" do
+ request = stub_request('CONTENT_TYPE' => 'application/xml; charset=UTF-8',
+ 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest")
assert_equal [Mime::XML], request.formats
+ end
+ test "formats format:text with accept header" do
request = stub_request
request.expects(:parameters).at_least_once.returns({ :format => :txt })
assert_equal [Mime::TEXT], request.formats
+ end
+ test "formats format:unknown with accept header" do
request = stub_request
request.expects(:parameters).at_least_once.returns({ :format => :unknown })
assert_instance_of Mime::NullType, request.format
@@ -616,10 +792,10 @@ class RequestTest < ActiveSupport::TestCase
test "format is not nil with unknown format" do
request = stub_request
request.expects(:parameters).at_least_once.returns({ format: :hello })
- assert_equal request.format.nil?, true
- assert_equal request.format.html?, false
- assert_equal request.format.xml?, false
- assert_equal request.format.json?, false
+ assert request.format.nil?
+ assert_not request.format.html?
+ assert_not request.format.xml?
+ assert_not request.format.json?
end
test "formats with xhr request" do
@@ -629,6 +805,7 @@ class RequestTest < ActiveSupport::TestCase
end
test "ignore_accept_header" do
+ old_ignore_accept_header = ActionDispatch::Request.ignore_accept_header
ActionDispatch::Request.ignore_accept_header = true
begin
@@ -658,33 +835,90 @@ class RequestTest < ActiveSupport::TestCase
request.expects(:parameters).at_least_once.returns({:format => :json})
assert_equal [ Mime::JSON ], request.formats
ensure
- ActionDispatch::Request.ignore_accept_header = false
+ ActionDispatch::Request.ignore_accept_header = old_ignore_accept_header
end
end
+end
- test "negotiate_mime" do
- request = stub_request 'HTTP_ACCEPT' => 'text/html',
- 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
+class RequestMimeType < BaseRequestTest
+ test "content type" do
+ assert_equal Mime::HTML, stub_request('CONTENT_TYPE' => 'text/html').content_mime_type
+ end
- request.expects(:parameters).at_least_once.returns({})
+ test "no content type" do
+ assert_equal nil, stub_request.content_mime_type
+ end
+
+ test "content type is XML" do
+ assert_equal Mime::XML, stub_request('CONTENT_TYPE' => 'application/xml').content_mime_type
+ end
+
+ test "content type with charset" do
+ assert_equal Mime::XML, stub_request('CONTENT_TYPE' => 'application/xml; charset=UTF-8').content_mime_type
+ end
+
+ test "user agent" do
+ assert_equal 'TestAgent', stub_request('HTTP_USER_AGENT' => 'TestAgent').user_agent
+ end
+
+ test "negotiate_mime" do
+ request = stub_request(
+ 'HTTP_ACCEPT' => 'text/html',
+ 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
+ )
assert_equal nil, request.negotiate_mime([Mime::XML, Mime::JSON])
assert_equal Mime::HTML, request.negotiate_mime([Mime::XML, Mime::HTML])
assert_equal Mime::HTML, request.negotiate_mime([Mime::XML, Mime::ALL])
+ end
+
+ test "negotiate_mime with content_type" do
+ request = stub_request(
+ 'CONTENT_TYPE' => 'application/xml; charset=UTF-8',
+ 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
+ )
- request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8',
- 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
- request.expects(:parameters).at_least_once.returns({})
assert_equal Mime::XML, request.negotiate_mime([Mime::XML, Mime::CSV])
end
+end
- test "raw_post rewinds rack.input if RAW_POST_DATA is nil" do
- request = stub_request('rack.input' => StringIO.new("foo"),
- 'CONTENT_LENGTH' => 3)
- assert_equal "foo", request.raw_post
- assert_equal "foo", request.env['rack.input'].read
+class RequestParameters < BaseRequestTest
+ test "parameters" do
+ request = stub_request
+ request.expects(:request_parameters).at_least_once.returns({ "foo" => 1 })
+ request.expects(:query_parameters).at_least_once.returns({ "bar" => 2 })
+
+ assert_equal({"foo" => 1, "bar" => 2}, request.parameters)
+ assert_equal({"foo" => 1}, request.request_parameters)
+ assert_equal({"bar" => 2}, request.query_parameters)
+ end
+
+ test "parameters still accessible after rack parse error" do
+ request = stub_request("QUERY_STRING" => "x[y]=1&x[y][][w]=2")
+
+ assert_raises(ActionController::BadRequest) do
+ # rack will raise a TypeError when parsing this query string
+ request.parameters
+ end
+
+ assert_equal({}, request.parameters)
end
+ test "we have access to the original exception" do
+ request = stub_request("QUERY_STRING" => "x[y]=1&x[y][][w]=2")
+
+ e = assert_raises(ActionController::BadRequest) do
+ # rack will raise a TypeError when parsing this query string
+ request.parameters
+ end
+
+ assert e.original_exception
+ assert_equal e.original_exception.backtrace, e.backtrace
+ end
+end
+
+
+class RequestParameterFilter < BaseRequestTest
test "process parameter filter" do
test_hashes = [
[{'foo'=>'bar'},{'foo'=>'bar'},%w'food'],
@@ -713,9 +947,14 @@ class RequestTest < ActiveSupport::TestCase
end
test "filtered_parameters returns params filtered" do
- request = stub_request('action_dispatch.request.parameters' =>
- { 'lifo' => 'Pratik', 'amount' => '420', 'step' => '1' },
- 'action_dispatch.parameter_filter' => [:lifo, :amount])
+ request = stub_request(
+ 'action_dispatch.request.parameters' => {
+ 'lifo' => 'Pratik',
+ 'amount' => '420',
+ 'step' => '1'
+ },
+ 'action_dispatch.parameter_filter' => [:lifo, :amount]
+ )
params = request.filtered_parameters
assert_equal "[FILTERED]", params["lifo"]
@@ -724,10 +963,14 @@ class RequestTest < ActiveSupport::TestCase
end
test "filtered_env filters env as a whole" do
- request = stub_request('action_dispatch.request.parameters' =>
- { 'amount' => '420', 'step' => '1' }, "RAW_POST_DATA" => "yada yada",
- 'action_dispatch.parameter_filter' => [:lifo, :amount])
-
+ request = stub_request(
+ 'action_dispatch.request.parameters' => {
+ 'amount' => '420',
+ 'step' => '1'
+ },
+ "RAW_POST_DATA" => "yada yada",
+ 'action_dispatch.parameter_filter' => [:lifo, :amount]
+ )
request = stub_request(request.filtered_env)
assert_equal "[FILTERED]", request.raw_post
@@ -737,9 +980,11 @@ class RequestTest < ActiveSupport::TestCase
test "filtered_path returns path with filtered query string" do
%w(; &).each do |sep|
- request = stub_request('QUERY_STRING' => %w(username=sikachu secret=bd4f21f api_key=b1bc3b3cd352f68d79d7).join(sep),
+ request = stub_request(
+ 'QUERY_STRING' => %w(username=sikachu secret=bd4f21f api_key=b1bc3b3cd352f68d79d7).join(sep),
'PATH_INFO' => '/authenticate',
- 'action_dispatch.parameter_filter' => [:secret, :api_key])
+ 'action_dispatch.parameter_filter' => [:secret, :api_key]
+ )
path = request.filtered_path
assert_equal %w(/authenticate?username=sikachu secret=[FILTERED] api_key=[FILTERED]).join(sep), path
@@ -747,56 +992,40 @@ class RequestTest < ActiveSupport::TestCase
end
test "filtered_path should not unescape a genuine '[FILTERED]' value" do
- request = stub_request('QUERY_STRING' => "secret=bd4f21f&genuine=%5BFILTERED%5D",
+ request = stub_request(
+ 'QUERY_STRING' => "secret=bd4f21f&genuine=%5BFILTERED%5D",
'PATH_INFO' => '/authenticate',
- 'action_dispatch.parameter_filter' => [:secret])
+ 'action_dispatch.parameter_filter' => [:secret]
+ )
path = request.filtered_path
- assert_equal "/authenticate?secret=[FILTERED]&genuine=%5BFILTERED%5D", path
+ assert_equal request.script_name + "/authenticate?secret=[FILTERED]&genuine=%5BFILTERED%5D", path
end
test "filtered_path should preserve duplication of keys in query string" do
- request = stub_request('QUERY_STRING' => "username=sikachu&secret=bd4f21f&username=fxn",
+ request = stub_request(
+ 'QUERY_STRING' => "username=sikachu&secret=bd4f21f&username=fxn",
'PATH_INFO' => '/authenticate',
- 'action_dispatch.parameter_filter' => [:secret])
+ 'action_dispatch.parameter_filter' => [:secret]
+ )
path = request.filtered_path
- assert_equal "/authenticate?username=sikachu&secret=[FILTERED]&username=fxn", path
+ assert_equal request.script_name + "/authenticate?username=sikachu&secret=[FILTERED]&username=fxn", path
end
test "filtered_path should ignore searchparts" do
- request = stub_request('QUERY_STRING' => "secret",
+ request = stub_request(
+ 'QUERY_STRING' => "secret",
'PATH_INFO' => '/authenticate',
- 'action_dispatch.parameter_filter' => [:secret])
+ 'action_dispatch.parameter_filter' => [:secret]
+ )
path = request.filtered_path
- assert_equal "/authenticate?secret", path
- end
-
- test "original_fullpath returns ORIGINAL_FULLPATH" do
- request = stub_request('ORIGINAL_FULLPATH' => "/foo?bar")
-
- path = request.original_fullpath
- assert_equal "/foo?bar", path
- end
-
- test "original_url returns url built using ORIGINAL_FULLPATH" do
- request = stub_request('ORIGINAL_FULLPATH' => "/foo?bar",
- 'HTTP_HOST' => "example.org",
- 'rack.url_scheme' => "http")
-
- url = request.original_url
- assert_equal "http://example.org/foo?bar", url
- end
-
- test "original_fullpath returns fullpath if ORIGINAL_FULLPATH is not present" do
- request = stub_request('PATH_INFO' => "/foo",
- 'QUERY_STRING' => "bar")
-
- path = request.original_fullpath
- assert_equal "/foo?bar", path
+ assert_equal request.script_name + "/authenticate?secret", path
end
+end
+class RequestEtag < BaseRequestTest
test "if_none_match_etags none" do
request = stub_request
@@ -835,16 +1064,31 @@ class RequestTest < ActiveSupport::TestCase
assert request.etag_matches?(etag), etag
end
end
+end
+
+class RequestVarient < BaseRequestTest
+ test "setting variant" do
+ request = stub_request
+
+ request.variant = :mobile
+ assert_equal [:mobile], request.variant
-protected
+ request.variant = [:phone, :tablet]
+ assert_equal [:phone, :tablet], request.variant
- def stub_request(env = {})
- ip_spoofing_check = env.key?(:ip_spoofing_check) ? env.delete(:ip_spoofing_check) : true
- @trusted_proxies ||= nil
- ip_app = ActionDispatch::RemoteIp.new(Proc.new { }, ip_spoofing_check, @trusted_proxies)
- tld_length = env.key?(:tld_length) ? env.delete(:tld_length) : 1
- ip_app.call(env)
- ActionDispatch::Http::URL.tld_length = tld_length
- ActionDispatch::Request.new(env)
+ assert_raise ArgumentError do
+ request.variant = [:phone, "tablet"]
+ end
+
+ assert_raise ArgumentError do
+ request.variant = "yolo"
+ end
+ end
+
+ test "setting variant with non symbol value" do
+ request = stub_request
+ assert_raise ArgumentError do
+ request.variant = "mobile"
+ end
end
end
diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb
index 4501ea095c..187b9a2420 100644
--- a/actionpack/test/dispatch/response_test.rb
+++ b/actionpack/test/dispatch/response_test.rb
@@ -178,6 +178,7 @@ class ResponseTest < ActiveSupport::TestCase
end
test "read x_frame_options, x_content_type_options and x_xss_protection" do
+ original_default_headers = ActionDispatch::Response.default_headers
begin
ActionDispatch::Response.default_headers = {
'X-Frame-Options' => 'DENY',
@@ -193,11 +194,12 @@ class ResponseTest < ActiveSupport::TestCase
assert_equal('nosniff', resp.headers['X-Content-Type-Options'])
assert_equal('1;', resp.headers['X-XSS-Protection'])
ensure
- ActionDispatch::Response.default_headers = nil
+ ActionDispatch::Response.default_headers = original_default_headers
end
end
test "read custom default_header" do
+ original_default_headers = ActionDispatch::Response.default_headers
begin
ActionDispatch::Response.default_headers = {
'X-XX-XXXX' => 'Here is my phone number'
@@ -209,7 +211,7 @@ class ResponseTest < ActiveSupport::TestCase
assert_equal('Here is my phone number', resp.headers['X-XX-XXXX'])
ensure
- ActionDispatch::Response.default_headers = nil
+ ActionDispatch::Response.default_headers = original_default_headers
end
end
@@ -217,6 +219,24 @@ class ResponseTest < ActiveSupport::TestCase
assert_not @response.respond_to?(:method_missing)
assert @response.respond_to?(:method_missing, true)
end
+
+ test "can be destructured into status, headers and an enumerable body" do
+ response = ActionDispatch::Response.new(404, { 'Content-Type' => 'text/plain' }, ['Not Found'])
+ status, headers, body = response
+
+ assert_equal 404, status
+ assert_equal({ 'Content-Type' => 'text/plain' }, headers)
+ assert_equal ['Not Found'], body.each.to_a
+ end
+
+ test "[response].flatten does not recurse infinitely" do
+ Timeout.timeout(1) do # use a timeout to prevent it stalling indefinitely
+ status, headers, body = [@response].flatten
+ assert_equal @response.status, status
+ assert_equal @response.headers, headers
+ assert_equal @response.body, body.each.to_a.join
+ end
+ end
end
class ResponseIntegrationTest < ActionDispatch::IntegrationTest
diff --git a/actionpack/test/dispatch/routing/inspector_test.rb b/actionpack/test/dispatch/routing/inspector_test.rb
index 4f97d28d2b..ff33dd5652 100644
--- a/actionpack/test/dispatch/routing/inspector_test.rb
+++ b/actionpack/test/dispatch/routing/inspector_test.rb
@@ -46,11 +46,32 @@ module ActionDispatch
assert_equal [
" Prefix Verb URI Pattern Controller#Action",
- "custom_assets GET /custom/assets(.:format) custom_assets#show",
- " blog /blog Blog::Engine",
+ "custom_assets GET /custom/assets(.:format) custom_assets#show",
+ " blog /blog Blog::Engine",
"",
"Routes for Blog::Engine:",
- "cart GET /cart(.:format) cart#show"
+ " cart GET /cart(.:format) cart#show"
+ ], output
+ end
+
+ def test_displaying_routes_for_engines_without_routes
+ engine = Class.new(Rails::Engine) do
+ def self.inspect
+ "Blog::Engine"
+ end
+ end
+ engine.routes.draw do
+ end
+
+ output = draw do
+ mount engine => "/blog", as: "blog"
+ end
+
+ assert_equal [
+ "Prefix Verb URI Pattern Controller#Action",
+ " blog /blog Blog::Engine",
+ "",
+ "Routes for Blog::Engine:"
], output
end
@@ -61,7 +82,7 @@ module ActionDispatch
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
- "cart GET /cart(.:format) cart#show"
+ " cart GET /cart(.:format) cart#show"
], output
end
@@ -72,7 +93,7 @@ module ActionDispatch
assert_equal [
" Prefix Verb URI Pattern Controller#Action",
- "custom_assets GET /custom/assets(.:format) custom_assets#show"
+ "custom_assets GET /custom/assets(.:format) custom_assets#show"
], output
end
@@ -101,7 +122,7 @@ module ActionDispatch
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
- "root GET / pages#main"
+ " root GET / pages#main"
], output
end
@@ -112,7 +133,7 @@ module ActionDispatch
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
- " GET /api/:action(.:format) api#:action"
+ " GET /api/:action(.:format) api#:action"
], output
end
@@ -123,7 +144,7 @@ module ActionDispatch
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
- " GET /:controller/:action(.:format) :controller#:action"
+ " GET /:controller/:action(.:format) :controller#:action"
], output
end
@@ -134,7 +155,7 @@ module ActionDispatch
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
- " GET /:controller(/:action(/:id))(.:format) :controller#:action {:id=>/\\d+/}"
+ " GET /:controller(/:action(/:id))(.:format) :controller#:action {:id=>/\\d+/}"
], output
end
@@ -145,7 +166,7 @@ module ActionDispatch
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
- %Q[ GET /photos/:id(.:format) photos#show {:format=>"jpg"}]
+ %Q[ GET /photos/:id(.:format) photos#show {:format=>"jpg"}]
], output
end
@@ -156,7 +177,30 @@ module ActionDispatch
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
- " GET /photos/:id(.:format) photos#show {:id=>/[A-Z]\\d{5}/}"
+ " GET /photos/:id(.:format) photos#show {:id=>/[A-Z]\\d{5}/}"
+ ], output
+ end
+
+ def test_rake_routes_shows_routes_with_dashes
+ output = draw do
+ get 'about-us' => 'pages#about_us'
+ get 'our-work/latest'
+
+ resources :photos, only: [:show] do
+ get 'user-favorites', on: :collection
+ get 'preview-photo', on: :member
+ get 'summary-text'
+ end
+ end
+
+ assert_equal [
+ " Prefix Verb URI Pattern Controller#Action",
+ " about_us GET /about-us(.:format) pages#about_us",
+ " our_work_latest GET /our-work/latest(.:format) our_work#latest",
+ "user_favorites_photos GET /photos/user-favorites(.:format) photos#user_favorites",
+ " preview_photo_photo GET /photos/:id/preview-photo(.:format) photos#preview_photo",
+ " photo_summary_text GET /photos/:photo_id/summary-text(.:format) photos#summary_text",
+ " photo GET /photos/:id(.:format) photos#show"
], output
end
@@ -172,7 +216,7 @@ module ActionDispatch
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
- " GET /foo/:id(.:format) #{RackApp.name} {:id=>/[A-Z]\\d{5}/}"
+ " GET /foo/:id(.:format) #{RackApp.name} {:id=>/[A-Z]\\d{5}/}"
], output
end
@@ -191,7 +235,7 @@ module ActionDispatch
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
- " /foo #{RackApp.name} {:constraint=>( my custom constraint )}"
+ " /foo #{RackApp.name} {:constraint=>( my custom constraint )}"
], output
end
@@ -203,6 +247,18 @@ module ActionDispatch
assert_no_match(/\/sprockets/, output.first)
end
+ def test_rake_routes_shows_route_defined_in_under_assets_prefix
+ output = draw do
+ scope '/sprockets' do
+ get '/foo' => 'foo#bar'
+ end
+ end
+ assert_equal [
+ "Prefix Verb URI Pattern Controller#Action",
+ " foo GET /sprockets/foo(.:format) foo#bar"
+ ], output
+ end
+
def test_redirect
output = draw do
get "/foo" => redirect("/foo/bar"), :constraints => { :subdomain => "admin" }
@@ -212,9 +268,9 @@ module ActionDispatch
assert_equal [
"Prefix Verb URI Pattern Controller#Action",
- " foo GET /foo(.:format) redirect(301, /foo/bar) {:subdomain=>\"admin\"}",
- " bar GET /bar(.:format) redirect(307, path: /foo/bar)",
- "foobar GET /foobar(.:format) redirect(301)"
+ " foo GET /foo(.:format) redirect(301, /foo/bar) {:subdomain=>\"admin\"}",
+ " bar GET /bar(.:format) redirect(307, path: /foo/bar)",
+ "foobar GET /foobar(.:format) redirect(301)"
], output
end
@@ -241,7 +297,7 @@ module ActionDispatch
end
assert_equal ["Prefix Verb URI Pattern Controller#Action",
- " GET /:controller(/:action) (?-mix:api\\/[^\\/]+)#:action"], output
+ " GET /:controller(/:action) (?-mix:api\\/[^\\/]+)#:action"], output
end
end
end
diff --git a/actionpack/test/dispatch/routing/route_set_test.rb b/actionpack/test/dispatch/routing/route_set_test.rb
index 0e488d2b88..c465d56bde 100644
--- a/actionpack/test/dispatch/routing/route_set_test.rb
+++ b/actionpack/test/dispatch/routing/route_set_test.rb
@@ -81,10 +81,6 @@ module ActionDispatch
end
private
- def clear!
- @set.clear!
- end
-
def draw(&block)
@set.draw(&block)
end
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index 3e9e90a950..778dbfc74d 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -99,6 +99,16 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
+ def test_namespace_without_controller_segment
+ draw do
+ namespace :admin do
+ get 'hello/:controllers/:action'
+ end
+ end
+ get '/admin/hello/foo/new'
+ assert_equal 'foo', @request.params["controllers"]
+ end
+
def test_session_singleton_resource
draw do
resource :session do
@@ -351,8 +361,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
draw do
controller(:global) do
get 'global/hide_notice'
- get 'global/export', :to => :export, :as => :export_request
- get '/export/:id/:file', :to => :export, :as => :export_download, :constraints => { :file => /.*/ }
+ get 'global/export', :action => :export, :as => :export_request
+ get '/export/:id/:file', :action => :export, :as => :export_download, :constraints => { :file => /.*/ }
get 'global/:action'
end
end
@@ -720,8 +730,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
draw do
resources :replies do
member do
- put :answer, :to => :mark_as_answer
- delete :answer, :to => :unmark_as_answer
+ put :answer, :action => :mark_as_answer
+ delete :answer, :action => :unmark_as_answer
end
end
end
@@ -1031,6 +1041,136 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal 'users/home#index', @response.body
end
+ def test_namespaced_shallow_routes_with_module_option
+ draw do
+ namespace :foo, module: 'bar' do
+ resources :posts, only: [:index, :show] do
+ resources :comments, only: [:index, :show], shallow: true
+ end
+ end
+ end
+
+ get '/foo/posts'
+ assert_equal '/foo/posts', foo_posts_path
+ assert_equal 'bar/posts#index', @response.body
+
+ get '/foo/posts/1'
+ assert_equal '/foo/posts/1', foo_post_path('1')
+ assert_equal 'bar/posts#show', @response.body
+
+ get '/foo/posts/1/comments'
+ assert_equal '/foo/posts/1/comments', foo_post_comments_path('1')
+ assert_equal 'bar/comments#index', @response.body
+
+ get '/foo/comments/2'
+ assert_equal '/foo/comments/2', foo_comment_path('2')
+ assert_equal 'bar/comments#show', @response.body
+ end
+
+ def test_namespaced_shallow_routes_with_path_option
+ draw do
+ namespace :foo, path: 'bar' do
+ resources :posts, only: [:index, :show] do
+ resources :comments, only: [:index, :show], shallow: true
+ end
+ end
+ end
+
+ get '/bar/posts'
+ assert_equal '/bar/posts', foo_posts_path
+ assert_equal 'foo/posts#index', @response.body
+
+ get '/bar/posts/1'
+ assert_equal '/bar/posts/1', foo_post_path('1')
+ assert_equal 'foo/posts#show', @response.body
+
+ get '/bar/posts/1/comments'
+ assert_equal '/bar/posts/1/comments', foo_post_comments_path('1')
+ assert_equal 'foo/comments#index', @response.body
+
+ get '/bar/comments/2'
+ assert_equal '/bar/comments/2', foo_comment_path('2')
+ assert_equal 'foo/comments#show', @response.body
+ end
+
+ def test_namespaced_shallow_routes_with_as_option
+ draw do
+ namespace :foo, as: 'bar' do
+ resources :posts, only: [:index, :show] do
+ resources :comments, only: [:index, :show], shallow: true
+ end
+ end
+ end
+
+ get '/foo/posts'
+ assert_equal '/foo/posts', bar_posts_path
+ assert_equal 'foo/posts#index', @response.body
+
+ get '/foo/posts/1'
+ assert_equal '/foo/posts/1', bar_post_path('1')
+ assert_equal 'foo/posts#show', @response.body
+
+ get '/foo/posts/1/comments'
+ assert_equal '/foo/posts/1/comments', bar_post_comments_path('1')
+ assert_equal 'foo/comments#index', @response.body
+
+ get '/foo/comments/2'
+ assert_equal '/foo/comments/2', bar_comment_path('2')
+ assert_equal 'foo/comments#show', @response.body
+ end
+
+ def test_namespaced_shallow_routes_with_shallow_path_option
+ draw do
+ namespace :foo, shallow_path: 'bar' do
+ resources :posts, only: [:index, :show] do
+ resources :comments, only: [:index, :show], shallow: true
+ end
+ end
+ end
+
+ get '/foo/posts'
+ assert_equal '/foo/posts', foo_posts_path
+ assert_equal 'foo/posts#index', @response.body
+
+ get '/foo/posts/1'
+ assert_equal '/foo/posts/1', foo_post_path('1')
+ assert_equal 'foo/posts#show', @response.body
+
+ get '/foo/posts/1/comments'
+ assert_equal '/foo/posts/1/comments', foo_post_comments_path('1')
+ assert_equal 'foo/comments#index', @response.body
+
+ get '/bar/comments/2'
+ assert_equal '/bar/comments/2', foo_comment_path('2')
+ assert_equal 'foo/comments#show', @response.body
+ end
+
+ def test_namespaced_shallow_routes_with_shallow_prefix_option
+ draw do
+ namespace :foo, shallow_prefix: 'bar' do
+ resources :posts, only: [:index, :show] do
+ resources :comments, only: [:index, :show], shallow: true
+ end
+ end
+ end
+
+ get '/foo/posts'
+ assert_equal '/foo/posts', foo_posts_path
+ assert_equal 'foo/posts#index', @response.body
+
+ get '/foo/posts/1'
+ assert_equal '/foo/posts/1', foo_post_path('1')
+ assert_equal 'foo/posts#show', @response.body
+
+ get '/foo/posts/1/comments'
+ assert_equal '/foo/posts/1/comments', foo_post_comments_path('1')
+ assert_equal 'foo/comments#index', @response.body
+
+ get '/foo/comments/2'
+ assert_equal '/foo/comments/2', bar_comment_path('2')
+ assert_equal 'foo/comments#show', @response.body
+ end
+
def test_namespace_containing_numbers
draw do
namespace :v2 do
@@ -1048,7 +1188,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
controller :articles do
scope '/articles', :as => 'article' do
scope :path => '/:title', :title => /[a-z]+/, :as => :with_title do
- get '/:id', :to => :with_id, :as => ""
+ get '/:id', :action => :with_id, :as => ""
end
end
end
@@ -1295,7 +1435,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
def test_scoped_controller_with_namespace_and_action
draw do
namespace :account do
- get ':action/callback', :action => /twitter|github/, :to => "callbacks", :as => :callback
+ get ':action/callback', :action => /twitter|github/, :controller => "callbacks", :as => :callback
end
end
@@ -1352,7 +1492,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
def test_normalize_namespaced_matches
draw do
namespace :account do
- get 'description', :to => :description, :as => "description"
+ get 'description', :action => :description, :as => "description"
end
end
@@ -1593,7 +1733,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get "whatever/:controller(/:action(/:id))"
end
- get 'whatever/foo/bar'
+ get '/whatever/foo/bar'
assert_equal 'foo#bar', @response.body
assert_equal 'http://www.example.com/whatever/foo/bar/1',
@@ -1605,10 +1745,10 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get "whatever/:controller(/:action(/:id))", :id => /\d+/
end
- get 'whatever/foo/bar/show'
+ get '/whatever/foo/bar/show'
assert_equal 'foo/bar#show', @response.body
- get 'whatever/foo/bar/show/1'
+ get '/whatever/foo/bar/show/1'
assert_equal 'foo/bar#show', @response.body
assert_equal 'http://www.example.com/whatever/foo/bar/show',
@@ -1828,6 +1968,60 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal '/comments/3/preview', preview_comment_path(:id => '3')
end
+ def test_shallow_nested_resources_inside_resource
+ draw do
+ resource :membership, shallow: true do
+ resources :cards
+ end
+ end
+
+ get '/membership/cards'
+ assert_equal 'cards#index', @response.body
+ assert_equal '/membership/cards', membership_cards_path
+
+ get '/membership/cards/new'
+ assert_equal 'cards#new', @response.body
+ assert_equal '/membership/cards/new', new_membership_card_path
+
+ post '/membership/cards'
+ assert_equal 'cards#create', @response.body
+
+ get '/cards/1'
+ assert_equal 'cards#show', @response.body
+ assert_equal '/cards/1', card_path('1')
+
+ get '/cards/1/edit'
+ assert_equal 'cards#edit', @response.body
+ assert_equal '/cards/1/edit', edit_card_path('1')
+
+ put '/cards/1'
+ assert_equal 'cards#update', @response.body
+
+ patch '/cards/1'
+ assert_equal 'cards#update', @response.body
+
+ delete '/cards/1'
+ assert_equal 'cards#destroy', @response.body
+ end
+
+ def test_shallow_deeply_nested_resources
+ draw do
+ resources :blogs do
+ resources :posts do
+ resources :comments, shallow: true
+ end
+ end
+ end
+
+ get '/comments/1'
+ assert_equal 'comments#show', @response.body
+
+ assert_equal '/comments/1', comment_path('1')
+ assert_equal '/blogs/new', new_blog_path
+ assert_equal '/blogs/1/posts/new', new_blog_post_path(:blog_id => 1)
+ assert_equal '/blogs/1/posts/2/comments/new', new_blog_post_comment_path(:blog_id => 1, :post_id => 2)
+ end
+
def test_shallow_nested_resources_within_scope
draw do
scope '/hello' do
@@ -1889,6 +2083,65 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal 'notes#destroy', @response.body
end
+ def test_shallow_option_nested_resources_within_scope
+ draw do
+ scope '/hello' do
+ resources :notes, :shallow => true do
+ resources :trackbacks
+ end
+ end
+ end
+
+ get '/hello/notes/1/trackbacks'
+ assert_equal 'trackbacks#index', @response.body
+ assert_equal '/hello/notes/1/trackbacks', note_trackbacks_path(:note_id => 1)
+
+ get '/hello/notes/1/edit'
+ assert_equal 'notes#edit', @response.body
+ assert_equal '/hello/notes/1/edit', edit_note_path(:id => '1')
+
+ get '/hello/notes/1/trackbacks/new'
+ assert_equal 'trackbacks#new', @response.body
+ assert_equal '/hello/notes/1/trackbacks/new', new_note_trackback_path(:note_id => 1)
+
+ get '/hello/trackbacks/1'
+ assert_equal 'trackbacks#show', @response.body
+ assert_equal '/hello/trackbacks/1', trackback_path(:id => '1')
+
+ get '/hello/trackbacks/1/edit'
+ assert_equal 'trackbacks#edit', @response.body
+ assert_equal '/hello/trackbacks/1/edit', edit_trackback_path(:id => '1')
+
+ put '/hello/trackbacks/1'
+ assert_equal 'trackbacks#update', @response.body
+
+ post '/hello/notes/1/trackbacks'
+ assert_equal 'trackbacks#create', @response.body
+
+ delete '/hello/trackbacks/1'
+ assert_equal 'trackbacks#destroy', @response.body
+
+ get '/hello/notes'
+ assert_equal 'notes#index', @response.body
+
+ post '/hello/notes'
+ assert_equal 'notes#create', @response.body
+
+ get '/hello/notes/new'
+ assert_equal 'notes#new', @response.body
+ assert_equal '/hello/notes/new', new_note_path
+
+ get '/hello/notes/1'
+ assert_equal 'notes#show', @response.body
+ assert_equal '/hello/notes/1', note_path(:id => 1)
+
+ put '/hello/notes/1'
+ assert_equal 'notes#update', @response.body
+
+ delete '/hello/notes/1'
+ assert_equal 'notes#destroy', @response.body
+ end
+
def test_custom_resource_routes_are_scoped
draw do
resources :customers do
@@ -1901,7 +2154,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
resources :invoices do
get "outstanding" => "invoices#outstanding", :on => :collection
- get "overdue", :to => :overdue, :on => :collection
+ get "overdue", :action => :overdue, :on => :collection
get "print" => "invoices#print", :as => :print, :on => :member
post "preview" => "invoices#preview", :as => :preview, :on => :new
end
@@ -1989,6 +2242,22 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal '/api/1.0/users/first.last.xml', api_user_path(:version => '1.0', :id => 'first.last', :format => :xml)
end
+ def test_match_without_via
+ assert_raises(ArgumentError) do
+ draw do
+ match '/foo/bar', :to => 'files#show'
+ end
+ end
+ end
+
+ def test_match_with_empty_via
+ assert_raises(ArgumentError) do
+ draw do
+ match '/foo/bar', :to => 'files#show', :via => []
+ end
+ end
+ end
+
def test_glob_parameter_accepts_regexp
draw do
get '/:locale/*file.:format', :to => 'files#show', :file => /path\/to\/existing\/file/
@@ -2044,12 +2313,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get "(/user/:username)/photos" => "photos#index"
end
- get 'user/bob/photos'
+ get '/user/bob/photos'
assert_equal 'photos#index', @response.body
assert_equal 'http://www.example.com/user/bob/photos',
url_for(:controller => "photos", :action => "index", :username => "bob")
- get 'photos'
+ get '/photos'
assert_equal 'photos#index', @response.body
assert_equal 'http://www.example.com/photos',
url_for(:controller => "photos", :action => "index", :username => nil)
@@ -2727,7 +2996,9 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
assert_raise(ArgumentError) do
- draw { controller("/feeds") { get '/feeds/:service', :to => :show } }
+ assert_deprecated do
+ draw { controller("/feeds") { get '/feeds/:service', :to => :show } }
+ end
end
assert_raise(ArgumentError) do
@@ -2864,6 +3135,288 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert !@request.params[:action].frozen?
end
+ def test_multiple_positional_args_with_the_same_name
+ draw do
+ get '/downloads/:id/:id.tar' => 'downloads#show', as: :download, format: false
+ end
+
+ expected_params = {
+ controller: 'downloads',
+ action: 'show',
+ id: '1'
+ }
+
+ get '/downloads/1/1.tar'
+ assert_equal 'downloads#show', @response.body
+ assert_equal expected_params, @request.symbolized_path_parameters
+ assert_equal '/downloads/1/1.tar', download_path('1')
+ assert_equal '/downloads/1/1.tar', download_path('1', '1')
+ end
+
+ def test_absolute_controller_namespace
+ draw do
+ namespace :foo do
+ get '/', to: '/bar#index', as: 'root'
+ end
+ end
+
+ get '/foo'
+ assert_equal 'bar#index', @response.body
+ assert_equal '/foo', foo_root_path
+ end
+
+ def test_namespace_as_controller
+ draw do
+ namespace :foo do
+ get '/', to: '/bar#index', as: 'root'
+ end
+ end
+
+ get '/foo'
+ assert_equal 'bar#index', @response.body
+ assert_equal '/foo', foo_root_path
+ end
+
+ def test_trailing_slash
+ draw do
+ resources :streams
+ end
+
+ get '/streams'
+ assert @response.ok?, 'route without trailing slash should work'
+
+ get '/streams/'
+ assert @response.ok?, 'route with trailing slash should work'
+
+ get '/streams?foobar'
+ assert @response.ok?, 'route without trailing slash and with QUERY_STRING should work'
+
+ get '/streams/?foobar'
+ assert @response.ok?, 'route with trailing slash and with QUERY_STRING should work'
+ end
+
+ def test_route_with_dashes_in_path
+ draw do
+ get '/contact-us', to: 'pages#contact_us'
+ end
+
+ get '/contact-us'
+ assert_equal 'pages#contact_us', @response.body
+ assert_equal '/contact-us', contact_us_path
+ end
+
+ def test_shorthand_route_with_dashes_in_path
+ draw do
+ get '/about-us/index'
+ end
+
+ get '/about-us/index'
+ assert_equal 'about_us#index', @response.body
+ assert_equal '/about-us/index', about_us_index_path
+ end
+
+ def test_resource_routes_with_dashes_in_path
+ draw do
+ resources :photos, only: [:show] do
+ get 'user-favorites', on: :collection
+ get 'preview-photo', on: :member
+ get 'summary-text'
+ end
+ end
+
+ get '/photos/user-favorites'
+ assert_equal 'photos#user_favorites', @response.body
+ assert_equal '/photos/user-favorites', user_favorites_photos_path
+
+ get '/photos/1/preview-photo'
+ assert_equal 'photos#preview_photo', @response.body
+ assert_equal '/photos/1/preview-photo', preview_photo_photo_path('1')
+
+ get '/photos/1/summary-text'
+ assert_equal 'photos#summary_text', @response.body
+ assert_equal '/photos/1/summary-text', photo_summary_text_path('1')
+
+ get '/photos/1'
+ assert_equal 'photos#show', @response.body
+ assert_equal '/photos/1', photo_path('1')
+ end
+
+ def test_shallow_path_inside_namespace_is_not_added_twice
+ draw do
+ namespace :admin do
+ shallow do
+ resources :posts do
+ resources :comments
+ end
+ end
+ end
+ end
+
+ get '/admin/posts/1/comments'
+ assert_equal 'admin/comments#index', @response.body
+ assert_equal '/admin/posts/1/comments', admin_post_comments_path('1')
+ end
+
+ def test_mix_string_to_controller_action
+ draw do
+ get '/projects', controller: 'project_files',
+ action: 'index',
+ to: 'comments#index'
+ end
+ get '/projects'
+ assert_equal 'comments#index', @response.body
+ end
+
+ def test_mix_string_to_controller
+ draw do
+ get '/projects', controller: 'project_files',
+ to: 'comments#index'
+ end
+ get '/projects'
+ assert_equal 'comments#index', @response.body
+ end
+
+ def test_mix_string_to_action
+ draw do
+ get '/projects', action: 'index',
+ to: 'comments#index'
+ end
+ get '/projects'
+ assert_equal 'comments#index', @response.body
+ end
+
+ def test_mix_symbol_to_controller_action
+ assert_deprecated do
+ draw do
+ get '/projects', controller: 'project_files',
+ action: 'index',
+ to: :show
+ end
+ end
+ get '/projects'
+ assert_equal 'project_files#show', @response.body
+ end
+
+ def test_mix_string_to_controller_action_no_hash
+ assert_deprecated do
+ draw do
+ get '/projects', controller: 'project_files',
+ action: 'index',
+ to: 'show'
+ end
+ end
+ get '/projects'
+ assert_equal 'show#index', @response.body
+ end
+
+ def test_shallow_path_and_prefix_are_not_added_to_non_shallow_routes
+ draw do
+ scope shallow_path: 'projects', shallow_prefix: 'project' do
+ resources :projects do
+ resources :files, controller: 'project_files', shallow: true
+ end
+ end
+ end
+
+ get '/projects'
+ assert_equal 'projects#index', @response.body
+ assert_equal '/projects', projects_path
+
+ get '/projects/new'
+ assert_equal 'projects#new', @response.body
+ assert_equal '/projects/new', new_project_path
+
+ post '/projects'
+ assert_equal 'projects#create', @response.body
+
+ get '/projects/1'
+ assert_equal 'projects#show', @response.body
+ assert_equal '/projects/1', project_path('1')
+
+ get '/projects/1/edit'
+ assert_equal 'projects#edit', @response.body
+ assert_equal '/projects/1/edit', edit_project_path('1')
+
+ patch '/projects/1'
+ assert_equal 'projects#update', @response.body
+
+ delete '/projects/1'
+ assert_equal 'projects#destroy', @response.body
+
+ get '/projects/1/files'
+ assert_equal 'project_files#index', @response.body
+ assert_equal '/projects/1/files', project_files_path('1')
+
+ get '/projects/1/files/new'
+ assert_equal 'project_files#new', @response.body
+ assert_equal '/projects/1/files/new', new_project_file_path('1')
+
+ post '/projects/1/files'
+ assert_equal 'project_files#create', @response.body
+
+ get '/projects/files/2'
+ assert_equal 'project_files#show', @response.body
+ assert_equal '/projects/files/2', project_file_path('2')
+
+ get '/projects/files/2/edit'
+ assert_equal 'project_files#edit', @response.body
+ assert_equal '/projects/files/2/edit', edit_project_file_path('2')
+
+ patch '/projects/files/2'
+ assert_equal 'project_files#update', @response.body
+
+ delete '/projects/files/2'
+ assert_equal 'project_files#destroy', @response.body
+ end
+
+ def test_scope_path_is_copied_to_shallow_path
+ draw do
+ scope path: 'foo' do
+ resources :posts do
+ resources :comments, shallow: true
+ end
+ end
+ end
+
+ assert_equal '/foo/comments/1', comment_path('1')
+ end
+
+ def test_scope_as_is_copied_to_shallow_prefix
+ draw do
+ scope as: 'foo' do
+ resources :posts do
+ resources :comments, shallow: true
+ end
+ end
+ end
+
+ assert_equal '/comments/1', foo_comment_path('1')
+ end
+
+ def test_scope_shallow_prefix_is_not_overwritten_by_as
+ draw do
+ scope as: 'foo', shallow_prefix: 'bar' do
+ resources :posts do
+ resources :comments, shallow: true
+ end
+ end
+ end
+
+ assert_equal '/comments/1', bar_comment_path('1')
+ end
+
+ def test_scope_shallow_path_is_not_overwritten_by_path
+ draw do
+ scope path: 'foo', shallow_path: 'bar' do
+ resources :posts do
+ resources :comments, shallow: true
+ end
+ end
+ end
+
+ assert_equal '/bar/comments/1', comment_path('1')
+ end
+
private
def draw(&block)
@@ -2907,12 +3460,14 @@ end
class TestAltApp < ActionDispatch::IntegrationTest
class AltRequest
+ attr_accessor :path_parameters, :path_info, :script_name
+ attr_reader :env
+
def initialize(env)
+ @path_parameters = {}
@env = env
- end
-
- def path_info
- "/"
+ @path_info = "/"
+ @script_name = ""
end
def request_method
@@ -3015,6 +3570,35 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest
@app.draw(&block)
end
+ def test_missing_controller
+ ex = assert_raises(ArgumentError) {
+ draw do
+ get '/foo/bar', :action => :index
+ end
+ }
+ assert_match(/Missing :controller/, ex.message)
+ end
+
+ def test_missing_action
+ ex = assert_raises(ArgumentError) {
+ assert_deprecated do
+ draw do
+ get '/foo/bar', :to => 'foo'
+ end
+ end
+ }
+ assert_match(/Missing :action/, ex.message)
+ end
+
+ def test_missing_action_on_hash
+ ex = assert_raises(ArgumentError) {
+ draw do
+ get '/foo/bar', :to => 'foo#'
+ end
+ }
+ assert_match(/Missing :action/, ex.message)
+ end
+
def test_valid_controller_options_inside_namespace
draw do
namespace :admin do
@@ -3031,7 +3615,7 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest
resources :storage_files, :controller => 'admin/storage_files'
end
- get 'storage_files'
+ get '/storage_files'
assert_equal "admin/storage_files#index", @response.body
end
@@ -3056,6 +3640,16 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest
assert_match "'Admin::StorageFiles' is not a supported controller name", e.message
end
+
+ def test_warn_with_ruby_constant_syntax_no_colons
+ e = assert_raise(ArgumentError) do
+ draw do
+ resources :storage_files, :controller => 'Admin'
+ end
+ end
+
+ assert_match "'Admin' is not a supported controller name", e.message
+ end
end
class TestDefaultScope < ActionDispatch::IntegrationTest
@@ -3092,6 +3686,7 @@ class TestHttpMethods < ActionDispatch::IntegrationTest
RFC3648 = %w(ORDERPATCH)
RFC3744 = %w(ACL)
RFC5323 = %w(SEARCH)
+ RFC4791 = %w(MKCALENDAR)
RFC5789 = %w(PATCH)
def simple_app(response)
@@ -3103,13 +3698,13 @@ class TestHttpMethods < ActionDispatch::IntegrationTest
@app = ActionDispatch::Routing::RouteSet.new
@app.draw do
- (RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC5789).each do |method|
+ (RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789).each do |method|
match '/' => s.simple_app(method), :via => method.underscore.to_sym
end
end
end
- (RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC5789).each do |method|
+ (RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789).each do |method|
test "request method #{method.underscore} can be matched" do
get '/', nil, 'REQUEST_METHOD' => method
assert_equal method, @response.body
@@ -3135,8 +3730,8 @@ class TestUriPathEscaping < ActionDispatch::IntegrationTest
include Routes.url_helpers
def app; Routes end
- test 'escapes generated path segment' do
- assert_equal '/a%20b/c+d', segment_path(:segment => 'a b/c+d')
+ test 'escapes slash in generated path segment' do
+ assert_equal '/a%20b%2Fc+d', segment_path(:segment => 'a b/c+d')
end
test 'unescapes recognized path segment' do
@@ -3144,7 +3739,7 @@ class TestUriPathEscaping < ActionDispatch::IntegrationTest
assert_equal 'a b/c+d', @response.body
end
- test 'escapes generated path splat' do
+ test 'does not escape slash in generated path splat' do
assert_equal '/a%20b/c+d', splat_path(:splat => 'a b/c+d')
end
@@ -3235,7 +3830,9 @@ class TestRedirectInterpolation < ActionDispatch::IntegrationTest
get "/foo/:id" => redirect("/foo/bar/%{id}")
get "/bar/:id" => redirect(:path => "/foo/bar/%{id}")
+ get "/baz/:id" => redirect("/baz?id=%{id}&foo=?&bar=1#id-%{id}")
get "/foo/bar/:id" => ok
+ get "/baz" => ok
end
end
@@ -3251,6 +3848,14 @@ class TestRedirectInterpolation < ActionDispatch::IntegrationTest
verify_redirect "http://www.example.com/foo/bar/1%3E"
end
+ test "path redirect escapes interpolated parameters correctly" do
+ get "/foo/1%201"
+ verify_redirect "http://www.example.com/foo/bar/1%201"
+
+ get "/baz/1%201"
+ verify_redirect "http://www.example.com/baz?id=1+1&foo=?&bar=1#id-1%201"
+ end
+
private
def verify_redirect(url, status=301)
assert_equal status, @response.status
@@ -3317,6 +3922,10 @@ class TestOptimizedNamedRoutes < ActionDispatch::IntegrationTest
ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] }
get '/foo' => ok, as: :foo
get '/post(/:action(/:id))' => ok, as: :posts
+ get '/:foo/:foo_type/bars/:id' => ok, as: :bar
+ get '/projects/:id.:format' => ok, as: :project
+ get '/pages/:id' => ok, as: :page
+ get '/wiki/*page' => ok, as: :wiki
end
end
@@ -3339,6 +3948,36 @@ class TestOptimizedNamedRoutes < ActionDispatch::IntegrationTest
assert_equal '/post', Routes.url_helpers.posts_path
assert_equal '/post', posts_path
end
+
+ test 'segments with same prefix are replaced correctly' do
+ assert_equal '/foo/baz/bars/1', Routes.url_helpers.bar_path('foo', 'baz', '1')
+ assert_equal '/foo/baz/bars/1', bar_path('foo', 'baz', '1')
+ end
+
+ test 'segments separated with a period are replaced correctly' do
+ assert_equal '/projects/1.json', Routes.url_helpers.project_path(1, :json)
+ assert_equal '/projects/1.json', project_path(1, :json)
+ end
+
+ test 'segments with question marks are escaped' do
+ assert_equal '/pages/foo%3Fbar', Routes.url_helpers.page_path('foo?bar')
+ assert_equal '/pages/foo%3Fbar', page_path('foo?bar')
+ end
+
+ test 'segments with slashes are escaped' do
+ assert_equal '/pages/foo%2Fbar', Routes.url_helpers.page_path('foo/bar')
+ assert_equal '/pages/foo%2Fbar', page_path('foo/bar')
+ end
+
+ test 'glob segments with question marks are escaped' do
+ assert_equal '/wiki/foo%3Fbar', Routes.url_helpers.wiki_path('foo?bar')
+ assert_equal '/wiki/foo%3Fbar', wiki_path('foo?bar')
+ end
+
+ test 'glob segments with slashes are not escaped' do
+ assert_equal '/wiki/foo/bar', Routes.url_helpers.wiki_path('foo/bar')
+ assert_equal '/wiki/foo/bar', wiki_path('foo/bar')
+ end
end
class TestNamedRouteUrlHelpers < ActionDispatch::IntegrationTest
@@ -3452,7 +4091,7 @@ class TestInvalidUrls < ActionDispatch::IntegrationTest
set.draw do
get "/bar/:id", :to => redirect("/foo/show/%{id}")
get "/foo/show(/:id)", :to => "test_invalid_urls/foo#show"
- get "/foo(/:action(/:id))", :to => "test_invalid_urls/foo"
+ get "/foo(/:action(/:id))", :controller => "test_invalid_urls/foo"
get "/:controller(/:action(/:id))"
end
@@ -3606,6 +4245,19 @@ class TestFormatConstraints < ActionDispatch::IntegrationTest
end
end
+class TestCallableConstraintValidation < ActionDispatch::IntegrationTest
+ def test_constraint_with_object_not_callable
+ assert_raises(ArgumentError) do
+ ActionDispatch::Routing::RouteSet.new.tap do |app|
+ app.draw do
+ ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] }
+ get '/test', to: ok, constraints: Object.new
+ end
+ end
+ end
+ end
+end
+
class TestRouteDefaults < ActionDispatch::IntegrationTest
stub_controllers do |routes|
Routes = routes
@@ -3686,3 +4338,28 @@ class TestRedirectRouteGeneration < ActionDispatch::IntegrationTest
end
end
end
+
+class TestUrlGenerationErrors < ActionDispatch::IntegrationTest
+ Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
+ app.draw do
+ get "/products/:id" => 'products#show', :as => :product
+ end
+ end
+
+ def app; Routes end
+
+ include Routes.url_helpers
+
+ test "url helpers raise a helpful error message whem generation fails" do
+ url, missing = { action: 'show', controller: 'products', id: nil }, [:id]
+ message = "No route matches #{url.inspect} missing required keys: #{missing.inspect}"
+
+ # Optimized url helper
+ error = assert_raises(ActionController::UrlGenerationError){ product_path(nil) }
+ assert_equal message, error.message
+
+ # Non-optimized url helper
+ error = assert_raises(ActionController::UrlGenerationError, message){ product_path(id: nil) }
+ assert_equal message, error.message
+ end
+end
diff --git a/actionpack/test/dispatch/session/mem_cache_store_test.rb b/actionpack/test/dispatch/session/mem_cache_store_test.rb
index e53ce4195b..f7a06cfed4 100644
--- a/actionpack/test/dispatch/session/mem_cache_store_test.rb
+++ b/actionpack/test/dispatch/session/mem_cache_store_test.rb
@@ -1,4 +1,5 @@
require 'abstract_unit'
+require 'securerandom'
# You need to start a memcached server inorder to run these tests
class MemCacheStoreTest < ActionDispatch::IntegrationTest
@@ -48,6 +49,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
assert_response :success
assert_equal 'foo: "bar"', response.body
end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
end
def test_getting_nil_session_value
@@ -56,6 +59,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
assert_response :success
assert_equal 'foo: nil', response.body
end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
end
def test_getting_session_value_after_session_reset
@@ -75,6 +80,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
assert_response :success
assert_equal 'foo: nil', response.body, "data for this session should have been obliterated from memcached"
end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
end
def test_getting_from_nonexistent_session
@@ -84,6 +91,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
assert_equal 'foo: nil', response.body
assert_nil cookies['_session_id'], "should only create session on write, not read"
end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
end
def test_setting_session_value_after_session_reset
@@ -105,6 +114,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
assert_response :success
assert_not_equal session_id, response.body
end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
end
def test_getting_session_id
@@ -118,6 +129,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
assert_response :success
assert_equal session_id, response.body, "should be able to read session id without accessing the session hash"
end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
end
def test_deserializes_unloaded_class
@@ -132,6 +145,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
assert_response :success
end
end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
end
def test_doesnt_write_session_cookie_if_session_id_is_already_exists
@@ -144,6 +159,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
assert_response :success
assert_equal nil, headers['Set-Cookie'], "should not resend the cookie again if session_id cookie is already exists"
end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
end
def test_prevents_session_fixation
@@ -159,6 +176,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
assert_response :success
assert_not_equal session_id, cookies['_session_id']
end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
end
rescue LoadError, RuntimeError, Dalli::DalliError
$stderr.puts "Skipping MemCacheStoreTest tests. Start memcached and try again."
@@ -172,7 +191,7 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
end
@app = self.class.build_app(set) do |middleware|
- middleware.use ActionDispatch::Session::MemCacheStore, :key => '_session_id'
+ middleware.use ActionDispatch::Session::MemCacheStore, :key => '_session_id', :namespace => "mem_cache_store_test:#{SecureRandom.hex(10)}"
middleware.delete "ActionDispatch::ShowExceptions"
end
diff --git a/actionpack/test/dispatch/ssl_test.rb b/actionpack/test/dispatch/ssl_test.rb
index 94969f795a..c3598c5e8e 100644
--- a/actionpack/test/dispatch/ssl_test.rb
+++ b/actionpack/test/dispatch/ssl_test.rb
@@ -196,6 +196,13 @@ class SSLTest < ActionDispatch::IntegrationTest
response.headers['Location']
end
+ def test_redirect_to_host_with_port
+ self.app = ActionDispatch::SSL.new(default_app, :host => "ssl.example.org:443")
+ get "http://example.org/path?key=value"
+ assert_equal "https://ssl.example.org:443/path?key=value",
+ response.headers['Location']
+ end
+
def test_redirect_to_secure_host_when_on_subdomain
self.app = ActionDispatch::SSL.new(default_app, :host => "ssl.example.org")
get "http://ssl.example.org/path?key=value"
diff --git a/actionpack/test/dispatch/static_test.rb b/actionpack/test/dispatch/static_test.rb
index 112f470786..afdda70748 100644
--- a/actionpack/test/dispatch/static_test.rb
+++ b/actionpack/test/dispatch/static_test.rb
@@ -37,6 +37,8 @@ module StaticTests
end
def test_served_static_file_with_non_english_filename
+ jruby_skip "Stop skipping if following bug gets fixed: " \
+ "http://jira.codehaus.org/browse/JRUBY-7192"
assert_html "means hello in Japanese\n", get("/foo/#{Rack::Utils.escape("こんにちは.html")}")
end
@@ -133,11 +135,16 @@ module StaticTests
end
def with_static_file(file)
- path = "#{FIXTURE_LOAD_PATH}/public" + file
- File.open(path, "wb+") { |f| f.write(file) }
+ path = "#{FIXTURE_LOAD_PATH}/#{public_path}" + file
+ begin
+ File.open(path, "wb+") { |f| f.write(file) }
+ rescue Errno::EPROTO
+ skip "Couldn't create a file #{path}"
+ end
+
yield file
ensure
- File.delete(path)
+ File.delete(path) if File.exist? path
end
end
@@ -145,11 +152,24 @@ class StaticTest < ActiveSupport::TestCase
DummyApp = lambda { |env|
[200, {"Content-Type" => "text/plain"}, ["Hello, World!"]]
}
- App = ActionDispatch::Static.new(DummyApp, "#{FIXTURE_LOAD_PATH}/public", "public, max-age=60")
def setup
- @app = App
+ @app = ActionDispatch::Static.new(DummyApp, "#{FIXTURE_LOAD_PATH}/public", "public, max-age=60")
+ end
+
+ def public_path
+ "public"
end
include StaticTests
end
+
+class StaticEncodingTest < StaticTest
+ def setup
+ @app = ActionDispatch::Static.new(DummyApp, "#{FIXTURE_LOAD_PATH}/公共", "public, max-age=60")
+ end
+
+ def public_path
+ "公共"
+ end
+end
diff --git a/actionpack/test/dispatch/uploaded_file_test.rb b/actionpack/test/dispatch/uploaded_file_test.rb
index 72f3d1db0d..9f6381f118 100644
--- a/actionpack/test/dispatch/uploaded_file_test.rb
+++ b/actionpack/test/dispatch/uploaded_file_test.rb
@@ -33,6 +33,12 @@ module ActionDispatch
assert_equal 'foo', uf.tempfile
end
+ def test_to_io_returns_the_tempfile
+ tf = Object.new
+ uf = Http::UploadedFile.new(:tempfile => tf)
+ assert_equal tf, uf.to_io
+ end
+
def test_delegates_path_to_tempfile
tf = Class.new { def path; 'thunderhorse' end }
uf = Http::UploadedFile.new(:tempfile => tf.new)
diff --git a/actionpack/test/dispatch/url_generation_test.rb b/actionpack/test/dispatch/url_generation_test.rb
index f919592d24..a4dfd0a63d 100644
--- a/actionpack/test/dispatch/url_generation_test.rb
+++ b/actionpack/test/dispatch/url_generation_test.rb
@@ -15,6 +15,8 @@ module TestUrlGeneration
Routes.draw do
get "/foo", :to => "my_route_generating#index", :as => :foo
+ resources :bars
+
mount MyRouteGeneratingController.action(:index), at: '/bar'
end
@@ -64,18 +66,30 @@ module TestUrlGeneration
test "port is extracted from the host" do
assert_equal "http://www.example.com:8080/foo", foo_url(host: "www.example.com:8080", protocol: "http://")
+ assert_equal "//www.example.com:8080/foo", foo_url(host: "www.example.com:8080", protocol: "//")
+ assert_equal "//www.example.com:80/foo", foo_url(host: "www.example.com:80", protocol: "//")
+ end
+
+ test "port option is used" do
+ assert_equal "http://www.example.com:8080/foo", foo_url(host: "www.example.com", protocol: "http://", port: 8080)
+ assert_equal "//www.example.com:8080/foo", foo_url(host: "www.example.com", protocol: "//", port: 8080)
+ assert_equal "//www.example.com:80/foo", foo_url(host: "www.example.com", protocol: "//", port: 80)
end
- test "port option overides the host" do
+ test "port option overrides the host" do
assert_equal "http://www.example.com:8080/foo", foo_url(host: "www.example.com:8443", protocol: "http://", port: 8080)
+ assert_equal "//www.example.com:8080/foo", foo_url(host: "www.example.com:8443", protocol: "//", port: 8080)
+ assert_equal "//www.example.com:80/foo", foo_url(host: "www.example.com:443", protocol: "//", port: 80)
end
test "port option disables the host when set to nil" do
assert_equal "http://www.example.com/foo", foo_url(host: "www.example.com:8443", protocol: "http://", port: nil)
+ assert_equal "//www.example.com/foo", foo_url(host: "www.example.com:8443", protocol: "//", port: nil)
end
test "port option disables the host when set to false" do
assert_equal "http://www.example.com/foo", foo_url(host: "www.example.com:8443", protocol: "http://", port: false)
+ assert_equal "//www.example.com/foo", foo_url(host: "www.example.com:8443", protocol: "//", port: false)
end
test "keep subdomain when key is true" do
@@ -97,6 +111,22 @@ module TestUrlGeneration
test "omit subdomain when key is blank" do
assert_equal "http://example.com/foo", foo_url(subdomain: "")
end
+
+ test "generating URLs with trailing slashes" do
+ assert_equal "/bars.json", bars_path(
+ trailing_slash: true,
+ format: 'json'
+ )
+ end
+
+ test "generating URLS with querystring and trailing slashes" do
+ assert_equal "/bars.json?a=b", bars_path(
+ trailing_slash: true,
+ a: 'b',
+ format: 'json'
+ )
+ end
+
end
end