aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/test
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/test')
-rw-r--r--actionpack/test/abstract_unit.rb1
-rw-r--r--actionpack/test/controller/caching_test.rb40
-rw-r--r--actionpack/test/controller/params_wrapper_test.rb42
-rw-r--r--actionpack/test/controller/request_forgery_protection_test.rb1
-rw-r--r--actionpack/test/controller/rescue_test.rb11
-rw-r--r--actionpack/test/controller/url_for_test.rb20
-rw-r--r--actionpack/test/dispatch/debug_exceptions_test.rb9
-rw-r--r--actionpack/test/dispatch/exception_wrapper_test.rb16
-rw-r--r--actionpack/test/dispatch/request/session_test.rb2
-rw-r--r--actionpack/test/dispatch/request_test.rb102
-rw-r--r--actionpack/test/dispatch/response_test.rb12
-rw-r--r--actionpack/test/dispatch/session/abstract_store_test.rb4
-rw-r--r--actionpack/test/dispatch/ssl_test.rb297
13 files changed, 300 insertions, 257 deletions
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 1954324222..3c498960e4 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -406,7 +406,6 @@ def jruby_skip(message = '')
skip message if defined?(JRUBY_VERSION)
end
-require 'mocha/setup' # FIXME: stop using mocha
require 'active_support/testing/method_call_assertions'
class ForkingExecutor
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index 5698159eba..bc0ffd3eaa 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -299,30 +299,42 @@ class CacheHelperOutputBufferTest < ActionController::TestCase
def test_output_buffer
output_buffer = ActionView::OutputBuffer.new
controller = MockController.new
- cache_helper = Object.new
+ cache_helper = Class.new do
+ def self.controller; end;
+ def self.output_buffer; end;
+ def self.output_buffer=; end;
+ end
cache_helper.extend(ActionView::Helpers::CacheHelper)
- cache_helper.expects(:controller).returns(controller).at_least(0)
- cache_helper.expects(:output_buffer).returns(output_buffer).at_least(0)
- # if the output_buffer is changed, the new one should be html_safe and of the same type
- cache_helper.expects(:output_buffer=).with(responds_with(:html_safe?, true)).with(instance_of(output_buffer.class)).at_least(0)
- assert_nothing_raised do
- cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil }
+ cache_helper.stub :controller, controller do
+ cache_helper.stub :output_buffer, output_buffer do
+ assert_called_with cache_helper, :output_buffer=, [output_buffer.class.new(output_buffer)] do
+ assert_nothing_raised do
+ cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil }
+ end
+ end
+ end
end
end
def test_safe_buffer
output_buffer = ActiveSupport::SafeBuffer.new
controller = MockController.new
- cache_helper = Object.new
+ cache_helper = Class.new do
+ def self.controller; end;
+ def self.output_buffer; end;
+ def self.output_buffer=; end;
+ end
cache_helper.extend(ActionView::Helpers::CacheHelper)
- cache_helper.expects(:controller).returns(controller).at_least(0)
- cache_helper.expects(:output_buffer).returns(output_buffer).at_least(0)
- # if the output_buffer is changed, the new one should be html_safe and of the same type
- cache_helper.expects(:output_buffer=).with(responds_with(:html_safe?, true)).with(instance_of(output_buffer.class)).at_least(0)
- assert_nothing_raised do
- cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil }
+ cache_helper.stub :controller, controller do
+ cache_helper.stub :output_buffer, output_buffer do
+ assert_called_with cache_helper, :output_buffer=, [output_buffer.class.new(output_buffer)] do
+ assert_nothing_raised do
+ cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil }
+ end
+ end
+ end
end
end
end
diff --git a/actionpack/test/controller/params_wrapper_test.rb b/actionpack/test/controller/params_wrapper_test.rb
index 8bf016d060..7226beed26 100644
--- a/actionpack/test/controller/params_wrapper_test.rb
+++ b/actionpack/test/controller/params_wrapper_test.rb
@@ -28,8 +28,17 @@ class ParamsWrapperTest < ActionController::TestCase
end
end
- class User; end
- class Person; end
+ class User
+ def self.attribute_names
+ []
+ end
+ end
+
+ class Person
+ def self.attribute_names
+ []
+ end
+ end
tests UsersController
@@ -155,33 +164,28 @@ class ParamsWrapperTest < ActionController::TestCase
end
def test_derived_wrapped_keys_from_matching_model
- User.expects(:respond_to?).with(:attribute_names).returns(true)
- User.expects(:attribute_names).twice.returns(["username"])
-
- with_default_wrapper_options do
- @request.env['CONTENT_TYPE'] = 'application/json'
- post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' }
- assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu' }})
+ assert_called(User, :attribute_names, times: 2, returns: ["username"]) do
+ with_default_wrapper_options do
+ @request.env['CONTENT_TYPE'] = 'application/json'
+ post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' }
+ assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu' }})
+ end
end
end
def test_derived_wrapped_keys_from_specified_model
with_default_wrapper_options do
- Person.expects(:respond_to?).with(:attribute_names).returns(true)
- Person.expects(:attribute_names).twice.returns(["username"])
+ assert_called(Person, :attribute_names, times: 2, returns: ["username"]) do
+ UsersController.wrap_parameters Person
- UsersController.wrap_parameters Person
-
- @request.env['CONTENT_TYPE'] = 'application/json'
- post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' }
- assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'person' => { 'username' => 'sikachu' }})
+ @request.env['CONTENT_TYPE'] = 'application/json'
+ post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' }
+ assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'person' => { 'username' => 'sikachu' }})
+ end
end
end
def test_not_wrapping_abstract_model
- User.expects(:respond_to?).with(:attribute_names).returns(true)
- User.expects(:attribute_names).returns([])
-
with_default_wrapper_options do
@request.env['CONTENT_TYPE'] = 'application/json'
post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' }
diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb
index 90fd8669c2..94ffbe3cd0 100644
--- a/actionpack/test/controller/request_forgery_protection_test.rb
+++ b/actionpack/test/controller/request_forgery_protection_test.rb
@@ -379,7 +379,6 @@ module RequestForgeryProtectionTests
end
def test_should_not_raise_error_if_token_is_not_a_string
- @controller.unstub(:valid_authenticity_token?)
assert_blocked do
patch :index, params: { custom_authenticity_token: { foo: 'bar' } }
end
diff --git a/actionpack/test/controller/rescue_test.rb b/actionpack/test/controller/rescue_test.rb
index e767323773..f53f061e10 100644
--- a/actionpack/test/controller/rescue_test.rb
+++ b/actionpack/test/controller/rescue_test.rb
@@ -246,12 +246,15 @@ class RescueControllerTest < ActionController::TestCase
end
def test_rescue_handler_with_argument
- @controller.expects(:show_errors).once.with { |e| e.is_a?(Exception) }
- get :record_invalid
+ assert_called_with @controller, :show_errors, [Exception] do
+ get :record_invalid
+ end
end
+
def test_rescue_handler_with_argument_as_string
- @controller.expects(:show_errors).once.with { |e| e.is_a?(Exception) }
- get :record_invalid_raise_as_string
+ assert_called_with @controller, :show_errors, [Exception] do
+ get :record_invalid_raise_as_string
+ end
end
def test_proc_rescue_handler
diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb
index 31677f202d..78e883f134 100644
--- a/actionpack/test/controller/url_for_test.rb
+++ b/actionpack/test/controller/url_for_test.rb
@@ -451,6 +451,26 @@ module AbstractController
end
end
+ def test_url_for_with_array_is_unmodified
+ with_routing do |set|
+ set.draw do
+ namespace :admin do
+ resources :posts
+ end
+ end
+
+ kls = Class.new { include set.url_helpers }
+ kls.default_url_options[:host] = 'www.basecamphq.com'
+
+ original_components = [:new, :admin, :post, { param: 'value' }]
+ components = original_components.dup
+
+ kls.new.url_for(components)
+
+ assert_equal(original_components, components)
+ end
+ end
+
private
def extract_params(url)
url.split('?', 2).last.split('&').sort
diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb
index f9f379780c..93258fbceb 100644
--- a/actionpack/test/dispatch/debug_exceptions_test.rb
+++ b/actionpack/test/dispatch/debug_exceptions_test.rb
@@ -272,9 +272,12 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
test 'uses backtrace cleaner from env' do
@app = DevelopmentApp
- cleaner = stub(:clean => ['passed backtrace cleaner'])
- get "/", headers: { 'action_dispatch.show_exceptions' => true, 'action_dispatch.backtrace_cleaner' => cleaner }
- assert_match(/passed backtrace cleaner/, body)
+ backtrace_cleaner = ActiveSupport::BacktraceCleaner.new
+
+ backtrace_cleaner.stub :clean, ['passed backtrace cleaner'] do
+ get "/", headers: { 'action_dispatch.show_exceptions' => true, 'action_dispatch.backtrace_cleaner' => backtrace_cleaner }
+ assert_match(/passed backtrace cleaner/, body)
+ end
end
test 'logs exception backtrace when all lines silenced' do
diff --git a/actionpack/test/dispatch/exception_wrapper_test.rb b/actionpack/test/dispatch/exception_wrapper_test.rb
index f37cce4d45..dfbb91c0ca 100644
--- a/actionpack/test/dispatch/exception_wrapper_test.rb
+++ b/actionpack/test/dispatch/exception_wrapper_test.rb
@@ -25,27 +25,29 @@ module ActionDispatch
exception = TestError.new("lib/file.rb:42:in `index'")
wrapper = ExceptionWrapper.new(nil, exception)
- wrapper.expects(:source_fragment).with('lib/file.rb', 42).returns('foo')
-
- assert_equal [ code: 'foo', line_number: 42 ], wrapper.source_extracts
+ assert_called_with(wrapper, :source_fragment, ['lib/file.rb', 42], returns: 'foo') do
+ assert_equal [ code: 'foo', line_number: 42 ], wrapper.source_extracts
+ end
end
test '#source_extracts works with Windows paths' do
exc = TestError.new("c:/path/to/rails/app/controller.rb:27:in 'index':")
wrapper = ExceptionWrapper.new(nil, exc)
- wrapper.expects(:source_fragment).with('c:/path/to/rails/app/controller.rb', 27).returns('nothing')
- assert_equal [ code: 'nothing', line_number: 27 ], wrapper.source_extracts
+ assert_called_with(wrapper, :source_fragment, ['c:/path/to/rails/app/controller.rb', 27], returns: 'nothing') do
+ assert_equal [ code: 'nothing', line_number: 27 ], wrapper.source_extracts
+ end
end
test '#source_extracts works with non standard backtrace' do
exc = TestError.new('invalid')
wrapper = ExceptionWrapper.new(nil, exc)
- wrapper.expects(:source_fragment).with('invalid', 0).returns('nothing')
- assert_equal [ code: 'nothing', line_number: 0 ], wrapper.source_extracts
+ assert_called_with(wrapper, :source_fragment, ['invalid', 0], returns: 'nothing') do
+ assert_equal [ code: 'nothing', line_number: 0 ], wrapper.source_extracts
+ end
end
test '#application_trace returns traces only from the application' do
diff --git a/actionpack/test/dispatch/request/session_test.rb b/actionpack/test/dispatch/request/session_test.rb
index 410e3194e2..ae0e7e93ed 100644
--- a/actionpack/test/dispatch/request/session_test.rb
+++ b/actionpack/test/dispatch/request/session_test.rb
@@ -110,7 +110,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
+ def delete_session(env, id, options); 123; end
}.new
end
end
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index ff63c10e8d..258d097b7c 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -749,20 +749,23 @@ end
class RequestFormat < BaseRequestTest
test "xml format" do
request = stub_request
- request.expects(:parameters).at_least_once.returns({ :format => 'xml' })
- assert_equal Mime::XML, request.format
+ assert_called(request, :parameters, times: 2, returns: {format: :xml}) do
+ assert_equal Mime::XML, request.format
+ end
end
test "xhtml format" do
request = stub_request
- request.expects(:parameters).at_least_once.returns({ :format => 'xhtml' })
- assert_equal Mime::HTML, request.format
+ assert_called(request, :parameters, times: 2, returns: {format: :xhtml}) do
+ assert_equal Mime::HTML, request.format
+ end
end
test "txt format" do
request = stub_request
- request.expects(:parameters).at_least_once.returns({ :format => 'txt' })
- assert_equal Mime::TEXT, request.format
+ assert_called(request, :parameters, times: 2, returns: {format: :txt}) do
+ assert_equal Mime::TEXT, request.format
+ end
end
test "XMLHttpRequest" do
@@ -770,21 +773,25 @@ class RequestFormat < BaseRequestTest
'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
+
+ assert_called(request, :parameters, times: 1, returns: {}) do
+ assert request.xhr?
+ assert_equal Mime::JS, request.format
+ end
end
test "can override format with parameter negative" do
request = stub_request
- request.expects(:parameters).at_least_once.returns({ :format => :txt })
- assert !request.format.xml?
+ assert_called(request, :parameters, times: 2, returns: {format: :txt}) do
+ assert !request.format.xml?
+ end
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?
+ assert_called(request, :parameters, times: 2, returns: {format: :xml}) do
+ assert request.format.xml?
+ end
end
test "formats text/html with accept header" do
@@ -810,23 +817,26 @@ class RequestFormat < BaseRequestTest
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
+ assert_called(request, :parameters, times: 2, returns: {format: :txt}) do
+ assert_equal [Mime::TEXT], request.formats
+ end
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
+ assert_called(request, :parameters, times: 2, returns: {format: :unknown}) do
+ assert_instance_of Mime::NullType, request.format
+ end
end
test "format is not nil with unknown format" do
request = stub_request
- request.expects(:parameters).at_least_once.returns({ format: :hello })
- assert request.format.nil?
- assert_not request.format.html?
- assert_not request.format.xml?
- assert_not request.format.json?
+ assert_called(request, :parameters, times: 2, returns: {format: :hello}) do
+ assert request.format.nil?
+ assert_not request.format.html?
+ assert_not request.format.xml?
+ assert_not request.format.json?
+ end
end
test "format does not throw exceptions when malformed parameters" do
@@ -837,8 +847,9 @@ class RequestFormat < BaseRequestTest
test "formats with xhr request" do
request = stub_request 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
- request.expects(:parameters).at_least_once.returns({})
- assert_equal [Mime::JS], request.formats
+ assert_called(request, :parameters, times: 1, returns: {}) do
+ assert_equal [Mime::JS], request.formats
+ end
end
test "ignore_accept_header" do
@@ -847,30 +858,37 @@ class RequestFormat < BaseRequestTest
begin
request = stub_request 'HTTP_ACCEPT' => 'application/xml'
- request.expects(:parameters).at_least_once.returns({})
- assert_equal [ Mime::HTML ], request.formats
+ assert_called(request, :parameters, times: 1, returns: {}) do
+ assert_equal [ Mime::HTML ], request.formats
+ end
request = stub_request 'HTTP_ACCEPT' => 'koz-asked/something-crazy'
- request.expects(:parameters).at_least_once.returns({})
- assert_equal [ Mime::HTML ], request.formats
+ assert_called(request, :parameters, times: 1, returns: {}) do
+ assert_equal [ Mime::HTML ], request.formats
+ end
request = stub_request 'HTTP_ACCEPT' => '*/*;q=0.1'
- request.expects(:parameters).at_least_once.returns({})
- assert_equal [ Mime::HTML ], request.formats
+ assert_called(request, :parameters, times: 1, returns: {}) do
+ assert_equal [ Mime::HTML ], request.formats
+ end
request = stub_request 'HTTP_ACCEPT' => 'application/jxw'
- request.expects(:parameters).at_least_once.returns({})
- assert_equal [ Mime::HTML ], request.formats
+ assert_called(request, :parameters, times: 1, returns: {}) do
+ assert_equal [ Mime::HTML ], request.formats
+ end
request = stub_request 'HTTP_ACCEPT' => 'application/xml',
'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
- request.expects(:parameters).at_least_once.returns({})
- assert_equal [ Mime::JS ], request.formats
+
+ assert_called(request, :parameters, times: 1, returns: {}) do
+ assert_equal [ Mime::JS ], request.formats
+ end
request = stub_request 'HTTP_ACCEPT' => 'application/xml',
'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
- request.expects(:parameters).at_least_once.returns({:format => :json})
- assert_equal [ Mime::JSON ], request.formats
+ assert_called(request, :parameters, times: 2, returns: {format: :json}) do
+ assert_equal [ Mime::JSON ], request.formats
+ end
ensure
ActionDispatch::Request.ignore_accept_header = old_ignore_accept_header
end
@@ -922,12 +940,14 @@ end
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)
+ assert_called(request, :request_parameters, times: 2, returns: {"foo" => 1}) do
+ assert_called(request, :query_parameters, times: 2, returns: {"bar" => 2}) do
+ assert_equal({"foo" => 1, "bar" => 2}, request.parameters)
+ assert_equal({"foo" => 1}, request.request_parameters)
+ assert_equal({"bar" => 2}, request.query_parameters)
+ end
+ end
end
test "parameters not accessible after rack parse error" do
diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb
index 780e7dc3e2..5d74424de7 100644
--- a/actionpack/test/dispatch/response_test.rb
+++ b/actionpack/test/dispatch/response_test.rb
@@ -49,6 +49,11 @@ class ResponseTest < ActiveSupport::TestCase
assert_equal 'utf-8', @response.charset
end
+ def test_setting_content_type_header_impacts_content_type_method
+ @response.headers['Content-Type'] = "application/aaron"
+ assert_equal 'application/aaron', @response.content_type
+ end
+
test "simple output" do
@response.body = "Hello, World!"
@@ -67,6 +72,13 @@ class ResponseTest < ActiveSupport::TestCase
assert_equal 200, ActionDispatch::Response.new('200 OK').status
end
+ def test_only_set_charset_still_defaults_to_text_html
+ response = ActionDispatch::Response.new
+ response.charset = "utf-16"
+ _,headers,_ = response.to_a
+ assert_equal "text/html; charset=utf-16", headers['Content-Type']
+ end
+
test "utf8 output" do
@response.body = [1090, 1077, 1089, 1090].pack("U*")
diff --git a/actionpack/test/dispatch/session/abstract_store_test.rb b/actionpack/test/dispatch/session/abstract_store_test.rb
index 1c35144e6f..d38d1bbce6 100644
--- a/actionpack/test/dispatch/session/abstract_store_test.rb
+++ b/actionpack/test/dispatch/session/abstract_store_test.rb
@@ -10,13 +10,13 @@ module ActionDispatch
super
end
- def get_session(env, sid)
+ def find_session(env, sid)
sid ||= 1
session = @sessions[sid] ||= {}
[sid, session]
end
- def set_session(env, sid, session, options)
+ def write_session(env, sid, session, options)
@sessions[sid] = session
end
end
diff --git a/actionpack/test/dispatch/ssl_test.rb b/actionpack/test/dispatch/ssl_test.rb
index 017e9ba2dd..7a5b8393dc 100644
--- a/actionpack/test/dispatch/ssl_test.rb
+++ b/actionpack/test/dispatch/ssl_test.rb
@@ -1,230 +1,199 @@
require 'abstract_unit'
class SSLTest < ActionDispatch::IntegrationTest
- def default_app
- lambda { |env|
- headers = {'Content-Type' => "text/html"}
- headers['Set-Cookie'] = "id=1; path=/\ntoken=abc; path=/; secure; HttpOnly"
- [200, headers, ["OK"]]
+ HEADERS = Rack::Utils::HeaderHash.new 'Content-Type' => 'text/html'
+
+ attr_accessor :app
+
+ def build_app(headers: {}, ssl_options: {})
+ headers = HEADERS.merge(headers)
+ ActionDispatch::SSL.new lambda { |env| [200, headers, []] }, ssl_options
+ end
+end
+
+class RedirectSSLTest < SSLTest
+ def assert_not_redirected(url, headers: {})
+ self.app = build_app
+ get url, headers: headers
+ assert_response :ok
+ end
+
+ def assert_redirected(host: nil, port: nil, status: 301, body: [],
+ deprecated_host: nil, deprecated_port: nil,
+ from: 'http://a/b?c=d', to: from.sub('http', 'https'))
+
+ self.app = build_app ssl_options: {
+ redirect: { host: host, port: port, status: status, body: body },
+ host: deprecated_host, port: deprecated_port
}
+
+ get from
+ assert_response status
+ assert_redirected_to to
+ assert_equal body.join, @response.body
end
- def app
- @app ||= ActionDispatch::SSL.new(default_app)
+ test 'https is not redirected' do
+ assert_not_redirected 'https://example.org'
end
- attr_writer :app
- def test_allows_https_url
- get "https://example.org/path?key=value"
- assert_response :success
+ test 'proxied https is not redirected' do
+ assert_not_redirected 'http://example.org', headers: { 'HTTP_X_FORWARDED_PROTO' => 'https' }
end
- def test_allows_https_proxy_header_url
- get "http://example.org/", headers: { 'HTTP_X_FORWARDED_PROTO' => "https" }
- assert_response :success
+ test 'http is redirected to https' do
+ assert_redirected
end
- def test_redirects_http_to_https
- get "http://example.org/path?key=value"
- assert_response :redirect
- assert_equal "https://example.org/path?key=value",
- response.headers['Location']
+ test 'redirect with non-301 status' do
+ assert_redirected status: 307
end
- def test_hsts_header_by_default
- get "https://example.org/"
- assert_equal "max-age=31536000",
- response.headers['Strict-Transport-Security']
+ test 'redirect with custom body' do
+ assert_redirected body: ['foo']
end
- def test_no_hsts_with_insecure_connection
- get "http://example.org/"
- assert_not response.headers['Strict-Transport-Security']
+ test 'redirect to specific host' do
+ assert_redirected host: 'ssl', to: 'https://ssl/b?c=d'
end
- def test_hsts_header
- self.app = ActionDispatch::SSL.new(default_app, :hsts => true)
- get "https://example.org/"
- assert_equal "max-age=31536000",
- response.headers['Strict-Transport-Security']
+ test 'redirect to default port' do
+ assert_redirected port: 443
end
- def test_disable_hsts_header
- self.app = ActionDispatch::SSL.new(default_app, :hsts => false)
- get "https://example.org/"
- assert_not response.headers['Strict-Transport-Security']
+ test 'redirect to non-default port' do
+ assert_redirected port: 8443, to: 'https://a:8443/b?c=d'
end
- def test_hsts_expires
- self.app = ActionDispatch::SSL.new(default_app, :hsts => { :expires => 500 })
- get "https://example.org/"
- assert_equal "max-age=500",
- response.headers['Strict-Transport-Security']
+ test 'redirect to different host and non-default port' do
+ assert_redirected host: 'ssl', port: 8443, to: 'https://ssl:8443/b?c=d'
end
- def test_hsts_expires_with_duration
- self.app = ActionDispatch::SSL.new(default_app, :hsts => { :expires => 1.year })
- get "https://example.org/"
- assert_equal "max-age=31557600",
- response.headers['Strict-Transport-Security']
+ test 'redirect to different host including port' do
+ assert_redirected host: 'ssl:443', to: 'https://ssl:443/b?c=d'
end
- def test_hsts_include_subdomains
- self.app = ActionDispatch::SSL.new(default_app, :hsts => { :subdomains => true })
- get "https://example.org/"
- assert_equal "max-age=31536000; includeSubDomains",
- response.headers['Strict-Transport-Security']
+ test ':host is deprecated, moved within redirect: { host: … }' do
+ assert_deprecated do
+ assert_redirected deprecated_host: 'foo', to: 'https://foo/b?c=d'
+ end
end
- def test_flag_cookies_as_secure
- get "https://example.org/"
- assert_equal ["id=1; path=/; secure", "token=abc; path=/; secure; HttpOnly" ],
- response.headers['Set-Cookie'].split("\n")
+ test ':port is deprecated, moved within redirect: { port: … }' do
+ assert_deprecated do
+ assert_redirected deprecated_port: 1, to: 'https://a:1/b?c=d'
+ end
end
+end
- def test_flag_cookies_as_secure_at_end_of_line
- self.app = ActionDispatch::SSL.new(lambda { |env|
- headers = {
- 'Content-Type' => "text/html",
- 'Set-Cookie' => "problem=def; path=/; HttpOnly; secure"
- }
- [200, headers, ["OK"]]
- })
+class StrictTransportSecurityTest < SSLTest
+ EXPECTED = 'max-age=15552000'
- get "https://example.org/"
- assert_equal ["problem=def; path=/; HttpOnly; secure"],
- response.headers['Set-Cookie'].split("\n")
+ def assert_hsts(expected, url: 'https://example.org', hsts: {}, headers: {})
+ self.app = build_app ssl_options: { hsts: hsts }, headers: headers
+ get url
+ assert_equal expected, response.headers['Strict-Transport-Security']
end
- def test_flag_cookies_as_secure_with_more_spaces_before
- self.app = ActionDispatch::SSL.new(lambda { |env|
- headers = {
- 'Content-Type' => "text/html",
- 'Set-Cookie' => "problem=def; path=/; HttpOnly; secure"
- }
- [200, headers, ["OK"]]
- })
+ test 'enabled by default' do
+ assert_hsts EXPECTED
+ end
- get "https://example.org/"
- assert_equal ["problem=def; path=/; HttpOnly; secure"],
- response.headers['Set-Cookie'].split("\n")
+ test 'not sent with http:// responses' do
+ assert_hsts nil, url: 'http://example.org'
end
- def test_flag_cookies_as_secure_with_more_spaces_after
- self.app = ActionDispatch::SSL.new(lambda { |env|
- headers = {
- 'Content-Type' => "text/html",
- 'Set-Cookie' => "problem=def; path=/; secure; HttpOnly"
- }
- [200, headers, ["OK"]]
- })
+ test 'defers to app-provided header' do
+ assert_hsts 'app-provided', headers: { 'Strict-Transport-Security' => 'app-provided' }
+ end
- get "https://example.org/"
- assert_equal ["problem=def; path=/; secure; HttpOnly"],
- response.headers['Set-Cookie'].split("\n")
+ test 'hsts: true enables default settings' do
+ assert_hsts EXPECTED, hsts: true
end
+ test 'hsts: false sets max-age to zero, clearing browser HSTS settings' do
+ assert_hsts 'max-age=0', hsts: false
+ end
- def test_flag_cookies_as_secure_with_has_not_spaces_before
- self.app = ActionDispatch::SSL.new(lambda { |env|
- headers = {
- 'Content-Type' => "text/html",
- 'Set-Cookie' => "problem=def; path=/;secure; HttpOnly"
- }
- [200, headers, ["OK"]]
- })
+ test ':expires sets max-age' do
+ assert_hsts 'max-age=500', hsts: { expires: 500 }
+ end
- get "https://example.org/"
- assert_equal ["problem=def; path=/;secure; HttpOnly"],
- response.headers['Set-Cookie'].split("\n")
+ test ':expires supports AS::Duration arguments' do
+ assert_hsts 'max-age=31557600', hsts: { expires: 1.year }
end
- def test_flag_cookies_as_secure_with_has_not_spaces_after
- self.app = ActionDispatch::SSL.new(lambda { |env|
- headers = {
- 'Content-Type' => "text/html",
- 'Set-Cookie' => "problem=def; path=/; secure;HttpOnly"
- }
- [200, headers, ["OK"]]
- })
+ test 'include subdomains' do
+ assert_hsts "#{EXPECTED}; includeSubDomains", hsts: { subdomains: true }
+ end
- get "https://example.org/"
- assert_equal ["problem=def; path=/; secure;HttpOnly"],
- response.headers['Set-Cookie'].split("\n")
+ test 'exclude subdomains' do
+ assert_hsts EXPECTED, hsts: { subdomains: false }
end
- def test_flag_cookies_as_secure_with_ignore_case
- self.app = ActionDispatch::SSL.new(lambda { |env|
- headers = {
- 'Content-Type' => "text/html",
- 'Set-Cookie' => "problem=def; path=/; Secure; HttpOnly"
- }
- [200, headers, ["OK"]]
- })
+ test 'opt in to browser preload lists' do
+ assert_hsts "#{EXPECTED}; preload", hsts: { preload: true }
+ end
- get "https://example.org/"
- assert_equal ["problem=def; path=/; Secure; HttpOnly"],
- response.headers['Set-Cookie'].split("\n")
+ test 'opt out of browser preload lists' do
+ assert_hsts EXPECTED, hsts: { preload: false }
end
+end
- def test_no_cookies
- self.app = ActionDispatch::SSL.new(lambda { |env|
- [200, {'Content-Type' => "text/html"}, ["OK"]]
- })
- get "https://example.org/"
- assert !response.headers['Set-Cookie']
+class SecureCookiesTest < SSLTest
+ DEFAULT = %(id=1; path=/\ntoken=abc; path=/; secure; HttpOnly)
+
+ def get(**options)
+ self.app = build_app(**options)
+ super 'https://example.org'
+ end
+
+ def assert_cookies(*expected)
+ assert_equal expected, response.headers['Set-Cookie'].split("\n")
+ end
+
+ def test_flag_cookies_as_secure
+ get headers: { 'Set-Cookie' => DEFAULT }
+ assert_cookies 'id=1; path=/; secure', 'token=abc; path=/; secure; HttpOnly'
end
- def test_redirect_to_host
- self.app = ActionDispatch::SSL.new(default_app, :host => "ssl.example.org")
- get "http://example.org/path?key=value"
- assert_equal "https://ssl.example.org/path?key=value",
- response.headers['Location']
+ def test_flag_cookies_as_secure_at_end_of_line
+ get headers: { 'Set-Cookie' => 'problem=def; path=/; HttpOnly; secure' }
+ assert_cookies 'problem=def; path=/; HttpOnly; secure'
+ end
+
+ def test_flag_cookies_as_secure_with_more_spaces_before
+ get headers: { 'Set-Cookie' => 'problem=def; path=/; HttpOnly; secure' }
+ assert_cookies 'problem=def; path=/; HttpOnly; secure'
end
- def test_redirect_to_port
- self.app = ActionDispatch::SSL.new(default_app, :port => 8443)
- get "http://example.org/path?key=value"
- assert_equal "https://example.org:8443/path?key=value",
- response.headers['Location']
+ def test_flag_cookies_as_secure_with_more_spaces_after
+ get headers: { 'Set-Cookie' => 'problem=def; path=/; secure; HttpOnly' }
+ assert_cookies 'problem=def; path=/; secure; HttpOnly'
end
- def test_redirect_to_host_and_port
- self.app = ActionDispatch::SSL.new(default_app, :host => "ssl.example.org", :port => 8443)
- get "http://example.org/path?key=value"
- assert_equal "https://ssl.example.org:8443/path?key=value",
- response.headers['Location']
+ def test_flag_cookies_as_secure_with_has_not_spaces_before
+ get headers: { 'Set-Cookie' => 'problem=def; path=/;secure; HttpOnly' }
+ assert_cookies 'problem=def; path=/;secure; HttpOnly'
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']
+ def test_flag_cookies_as_secure_with_has_not_spaces_after
+ get headers: { 'Set-Cookie' => 'problem=def; path=/; secure;HttpOnly' }
+ assert_cookies 'problem=def; path=/; secure;HttpOnly'
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"
- assert_equal "https://ssl.example.org/path?key=value",
- response.headers['Location']
+ def test_flag_cookies_as_secure_with_ignore_case
+ get headers: { 'Set-Cookie' => 'problem=def; path=/; Secure; HttpOnly' }
+ assert_cookies 'problem=def; path=/; Secure; HttpOnly'
end
- def test_redirect_to_secure_subdomain_when_on_deep_subdomain
- self.app = ActionDispatch::SSL.new(default_app, :host => "example.co.uk")
- get "http://double.rainbow.what.does.it.mean.example.co.uk/path?key=value"
- assert_equal "https://example.co.uk/path?key=value",
- response.headers['Location']
+ def test_no_cookies
+ get
+ assert_nil response.headers['Set-Cookie']
end
def test_keeps_original_headers_behavior
- headers = Rack::Utils::HeaderHash.new(
- "Content-Type" => "text/html",
- "Connection" => ["close"]
- )
- self.app = ActionDispatch::SSL.new(lambda { |env| [200, headers, ["OK"]] })
-
- get "https://example.org/"
- assert_equal "close", response.headers["Connection"]
+ get headers: { 'Connection' => %w[close] }
+ assert_equal 'close', response.headers['Connection']
end
end