rails/actionpack/test/abstract_unit.rb
eileencodes 4276b214f8 Refactor to remove controller class from route to request
This refactoring moves the controller class name that was on the route
set to the request. The purpose of this refactoring is for changes we
need to move controller tests to integration tests, mainly being able to
access the controller on the request instead of having to go through
the router.

[Eileen M. Uchitelle & Aaron Patterson]
2015-08-22 09:44:24 -04:00

471 lines
12 KiB
Ruby

require File.expand_path('../../../load_paths', __FILE__)
$:.unshift(File.dirname(__FILE__) + '/lib')
$:.unshift(File.dirname(__FILE__) + '/fixtures/helpers')
$:.unshift(File.dirname(__FILE__) + '/fixtures/alternate_helpers')
require 'active_support/core_ext/kernel/reporting'
# These are the normal settings that will be set up by Railties
# TODO: Have these tests support other combinations of these values
silence_warnings do
Encoding.default_internal = "UTF-8"
Encoding.default_external = "UTF-8"
end
require 'drb'
begin
require 'drb/unix'
rescue LoadError
puts "'drb/unix' is not available"
end
require 'tempfile'
PROCESS_COUNT = (ENV['N'] || 4).to_i
require 'active_support/testing/autorun'
require 'abstract_controller'
require 'abstract_controller/railties/routes_helpers'
require 'action_controller'
require 'action_view'
require 'action_view/testing/resolvers'
require 'action_dispatch'
require 'active_support/dependencies'
require 'active_model'
require 'active_record'
require 'action_controller/caching'
require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late
module Rails
class << self
def env
@_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "test")
end
end
end
ActiveSupport::Dependencies.hook!
Thread.abort_on_exception = true
# Show backtraces for deprecated behavior for quicker cleanup.
ActiveSupport::Deprecation.debug = true
# Disable available locale checks to avoid warnings running the test suite.
I18n.enforce_available_locales = false
# Register danish language for testing
I18n.backend.store_translations 'da', {}
I18n.backend.store_translations 'pt-BR', {}
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
SharedTestRoutes = ActionDispatch::Routing::RouteSet.new
SharedTestRoutes.draw do
get ':controller(/:action)'
end
module ActionDispatch
module SharedRoutes
def before_setup
@routes = SharedTestRoutes
super
end
end
end
module ActiveSupport
class TestCase
if RUBY_ENGINE == "ruby" && PROCESS_COUNT > 0
parallelize_me!
end
end
end
class RoutedRackApp
attr_reader :routes
def initialize(routes, &blk)
@routes = routes
@stack = ActionDispatch::MiddlewareStack.new(&blk).build(@routes)
end
def call(env)
@stack.call(env)
end
end
class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
def self.build_app(routes = nil)
RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware|
middleware.use ActionDispatch::ShowExceptions, ActionDispatch::PublicExceptions.new("#{FIXTURE_LOAD_PATH}/public")
middleware.use ActionDispatch::DebugExceptions
middleware.use ActionDispatch::Callbacks
middleware.use ActionDispatch::ParamsParser
middleware.use ActionDispatch::Cookies
middleware.use ActionDispatch::Flash
middleware.use Rack::Head
yield(middleware) if block_given?
end
end
self.app = build_app
app.routes.draw do
get ':controller(/:action)'
end
# Stub Rails dispatcher so it does not get controller references and
# simply return the controller#action as Rack::Body.
class StubDispatcher < ::ActionDispatch::Routing::RouteSet::Dispatcher
protected
def controller_reference(controller_param)
controller_param.params[:controller]
end
def dispatch(controller, action, env)
[200, {'Content-Type' => 'text/html'}, ["#{controller}##{action}"]]
end
end
def self.stub_controllers(config = nil)
route_set = ActionDispatch::Routing::RouteSet.new(*[config].compact)
route_set.dispatcher_class = StubDispatcher
yield route_set
end
def with_routing(&block)
temporary_routes = ActionDispatch::Routing::RouteSet.new
old_app, self.class.app = self.class.app, self.class.build_app(temporary_routes)
old_routes = SharedTestRoutes
silence_warnings { Object.const_set(:SharedTestRoutes, temporary_routes) }
yield temporary_routes
ensure
self.class.app = old_app
self.remove!
silence_warnings { Object.const_set(:SharedTestRoutes, old_routes) }
end
def with_autoload_path(path)
path = File.join(File.dirname(__FILE__), "fixtures", path)
if ActiveSupport::Dependencies.autoload_paths.include?(path)
yield
else
begin
ActiveSupport::Dependencies.autoload_paths << path
yield
ensure
ActiveSupport::Dependencies.autoload_paths.reject! {|p| p == path}
ActiveSupport::Dependencies.clear
end
end
end
end
# Temporary base class
class Rack::TestCase < ActionDispatch::IntegrationTest
def self.testing(klass = nil)
if klass
@testing = "/#{klass.name.underscore}".sub!(/_controller$/, '')
else
@testing
end
end
def get(thing, *args)
if thing.is_a?(Symbol)
super("#{self.class.testing}/#{thing}", *args)
else
super
end
end
def assert_body(body)
assert_equal body, Array(response.body).join
end
def assert_status(code)
assert_equal code, response.status
end
def assert_response(body, status = 200, headers = {})
assert_body body
assert_status status
headers.each do |header, value|
assert_header header, value
end
end
def assert_content_type(type)
assert_equal type, response.headers["Content-Type"]
end
def assert_header(name, value)
assert_equal value, response.headers[name]
end
end
module ActionController
class API
extend AbstractController::Railties::RoutesHelpers.with(SharedTestRoutes)
end
class Base
# This stub emulates the Railtie including the URL helpers from a Rails application
extend AbstractController::Railties::RoutesHelpers.with(SharedTestRoutes)
include SharedTestRoutes.mounted_helpers
self.view_paths = FIXTURE_LOAD_PATH
def self.test_routes(&block)
routes = ActionDispatch::Routing::RouteSet.new
routes.draw(&block)
include routes.url_helpers
end
end
class TestCase
include ActionDispatch::TestProcess
include ActionDispatch::SharedRoutes
end
end
class ::ApplicationController < ActionController::Base
end
class Workshop
extend ActiveModel::Naming
include ActiveModel::Conversion
attr_accessor :id
def initialize(id)
@id = id
end
def persisted?
id.present?
end
def to_s
id.to_s
end
end
module ActionDispatch
class DebugExceptions
private
remove_method :stderr_logger
# Silence logger
def stderr_logger
nil
end
end
end
module ActionDispatch
module RoutingVerbs
def send_request(uri_or_host, method, path)
host = uri_or_host.host unless path
path ||= uri_or_host.path
params = {'PATH_INFO' => path,
'REQUEST_METHOD' => method,
'HTTP_HOST' => host}
routes.call(params)
end
def request_path_params(path, options = {})
method = options[:method] || 'GET'
resp = send_request URI('http://localhost' + path), method.to_s.upcase, nil
status = resp.first
if status == 404
raise ActionController::RoutingError, "No route matches #{path.inspect}"
end
controller.request.path_parameters
end
def get(uri_or_host, path = nil)
send_request(uri_or_host, 'GET', path)[2].join
end
def post(uri_or_host, path = nil)
send_request(uri_or_host, 'POST', path)[2].join
end
def put(uri_or_host, path = nil)
send_request(uri_or_host, 'PUT', path)[2].join
end
def delete(uri_or_host, path = nil)
send_request(uri_or_host, 'DELETE', path)[2].join
end
def patch(uri_or_host, path = nil)
send_request(uri_or_host, 'PATCH', path)[2].join
end
end
end
module RoutingTestHelpers
def url_for(set, options)
route_name = options.delete :use_route
set.url_for options.merge(:only_path => true), route_name
end
def make_set(strict = true)
tc = self
TestSet.new ->(c) { tc.controller = c }, strict
end
class TestSet < ActionDispatch::Routing::RouteSet
attr_reader :strict
def initialize(block, strict = false)
@block = block
@strict = strict
super()
end
class Dispatcher < ActionDispatch::Routing::RouteSet::Dispatcher
def initialize(defaults, set, block)
super(defaults)
@block = block
@set = set
end
def controller(params, default_controller=true)
super(params, @set.strict)
end
def controller_reference(controller_param)
block = @block
set = @set
super if @set.strict
Class.new(ActionController::Base) {
include set.url_helpers
define_method(:process) { |name| block.call(self) }
def to_a; [200, {}, []]; end
}
end
end
def dispatcher defaults
TestSet::Dispatcher.new defaults, self, @block
end
end
end
class ResourcesController < ActionController::Base
def index() head :ok end
alias_method :show, :index
end
class ThreadsController < ResourcesController; end
class MessagesController < ResourcesController; end
class CommentsController < ResourcesController; end
class ReviewsController < ResourcesController; end
class LogosController < ResourcesController; end
class AccountsController < ResourcesController; end
class AdminController < ResourcesController; end
class ProductsController < ResourcesController; end
class ImagesController < ResourcesController; end
class PreferencesController < ResourcesController; end
module Backoffice
class ProductsController < ResourcesController; end
class ImagesController < ResourcesController; end
module Admin
class ProductsController < ResourcesController; end
class ImagesController < ResourcesController; end
end
end
# Skips the current run on Rubinius using Minitest::Assertions#skip
def rubinius_skip(message = '')
skip message if RUBY_ENGINE == 'rbx'
end
# Skips the current run on JRuby using Minitest::Assertions#skip
def jruby_skip(message = '')
skip message if defined?(JRUBY_VERSION)
end
require 'mocha/setup' # FIXME: stop using mocha
class ForkingExecutor
class Server
include DRb::DRbUndumped
def initialize
@queue = Queue.new
end
def record reporter, result
reporter.record result
end
def << o
o[2] = DRbObject.new(o[2]) if o
@queue << o
end
def pop; @queue.pop; end
end
def initialize size
@size = size
@queue = Server.new
file = File.join Dir.tmpdir, Dir::Tmpname.make_tmpname('rails-tests', 'fd')
@url = "drbunix://#{file}"
@pool = nil
DRb.start_service @url, @queue
end
def << work; @queue << work; end
def shutdown
pool = @size.times.map {
fork {
DRb.stop_service
queue = DRbObject.new_with_uri @url
while job = queue.pop
klass = job[0]
method = job[1]
reporter = job[2]
result = Minitest.run_one_method klass, method
if result.error?
translate_exceptions result
end
queue.record reporter, result
end
}
}
@size.times { @queue << nil }
pool.each { |pid| Process.waitpid pid }
end
private
def translate_exceptions(result)
result.failures.map! { |e|
begin
Marshal.dump e
e
rescue TypeError
ex = Exception.new e.message
ex.set_backtrace e.backtrace
Minitest::UnexpectedError.new ex
end
}
end
end
if RUBY_ENGINE == "ruby" && PROCESS_COUNT > 0
# Use N processes (N defaults to 4)
Minitest.parallel_executor = ForkingExecutor.new(PROCESS_COUNT)
end