abstract_unit.rb 12.4 KB
Newer Older
1
require File.expand_path('../../../load_paths', __FILE__)
2

3
$:.unshift(File.dirname(__FILE__) + '/lib')
4
$:.unshift(File.dirname(__FILE__) + '/fixtures/helpers')
5
$:.unshift(File.dirname(__FILE__) + '/fixtures/alternate_helpers')
D
Initial  
David Heinemeier Hansson 已提交
6

J
Joshua Peek 已提交
7 8
ENV['TMPDIR'] = File.join(File.dirname(__FILE__), 'tmp')

9 10
require 'active_support/core_ext/kernel/reporting'

11 12 13 14 15
# 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"
16 17
end

18 19 20 21
require 'drb'
require 'drb/unix'
require 'tempfile'

22
require 'active_support/testing/autorun'
J
Joshua Peek 已提交
23
require 'abstract_controller'
24
require 'action_controller'
J
Joshua Peek 已提交
25
require 'action_view'
26
require 'action_view/testing/resolvers'
J
Joshua Peek 已提交
27
require 'action_dispatch'
28
require 'active_support/dependencies'
29
require 'active_model'
N
Neeraj Singh 已提交
30 31
require 'active_record'
require 'action_controller/caching'
32

J
Joshua Peek 已提交
33 34
require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late

35
module Rails
36 37 38 39 40
  class << self
    def env
      @_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "test")
    end
  end
41 42
end

43
ActiveSupport::Dependencies.hook!
44

45 46
Thread.abort_on_exception = true

47 48 49
# Show backtraces for deprecated behavior for quicker cleanup.
ActiveSupport::Deprecation.debug = true

50 51 52
# Disable available locale checks to avoid warnings running the test suite.
I18n.enforce_available_locales = false

J
Joshua Peek 已提交
53 54
# Register danish language for testing
I18n.backend.store_translations 'da', {}
55
I18n.backend.store_translations 'pt-BR', {}
56
ORIGINAL_LOCALES = I18n.available_locales.map {|locale| locale.to_s }.sort
J
Joshua Peek 已提交
57

Y
Yehuda Katz + Carl Lerche 已提交
58
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
59
FIXTURES = Pathname.new(FIXTURE_LOAD_PATH)
60

61 62 63 64 65 66 67 68 69 70 71 72 73
module RackTestUtils
  def body_to_string(body)
    if body.respond_to?(:each)
      str = ""
      body.each {|s| str << s }
      str
    else
      body
    end
  end
  extend self
end

C
Carlhuda 已提交
74 75
SharedTestRoutes = ActionDispatch::Routing::RouteSet.new

76 77 78 79 80 81 82 83
module ActionDispatch
  module SharedRoutes
    def before_setup
      @routes = SharedTestRoutes
      super
    end
  end

84 85 86 87 88 89 90 91 92 93 94 95
  # Hold off drawing routes until all the possible controller classes
  # have been loaded.
  module DrawOnce
    class << self
      attr_accessor :drew
    end
    self.drew = false

    def before_setup
      super
      return if DrawOnce.drew

96
      SharedTestRoutes.draw do
97
        get ':controller(/:action)'
C
Carlhuda 已提交
98 99
      end

100
      ActionDispatch::IntegrationTest.app.routes.draw do
101
        get ':controller(/:action)'
C
Carlhuda 已提交
102
      end
103 104

      DrawOnce.drew = true
J
Joshua Peek 已提交
105 106 107 108
    end
  end
end

109 110 111
module ActiveSupport
  class TestCase
    include ActionDispatch::DrawOnce
112
    parallelize_me! if ActiveSupport::Testing::Isolation.forking_env?
113 114 115
  end
end

C
Carlhuda 已提交
116
class RoutedRackApp
J
Joshua Peek 已提交
117
  attr_reader :routes
C
Carlhuda 已提交
118

J
Joshua Peek 已提交
119 120 121
  def initialize(routes, &blk)
    @routes = routes
    @stack = ActionDispatch::MiddlewareStack.new(&blk).build(@routes)
C
Carlhuda 已提交
122 123 124 125 126 127 128
  end

  def call(env)
    @stack.call(env)
  end
end

129
class BasicController
130
  attr_accessor :request
131 132

  def config
133
    @config ||= ActiveSupport::InheritableOptions.new(ActionController::Base.config).tap do |config|
134 135 136 137 138
      # VIEW TODO: View tests should not require a controller
      public_dir = File.expand_path("../fixtures/public", __FILE__)
      config.assets_dir = public_dir
      config.javascripts_dir = "#{public_dir}/javascripts"
      config.stylesheets_dir = "#{public_dir}/stylesheets"
139
      config.assets          = ActiveSupport::InheritableOptions.new({ :prefix => "assets" })
140 141 142 143 144
      config
    end
  end
end

145
class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
146
  include ActionDispatch::SharedRoutes
147

148
  def self.build_app(routes = nil)
C
Carlhuda 已提交
149
    RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware|
150
      middleware.use "ActionDispatch::ShowExceptions", ActionDispatch::PublicExceptions.new("#{FIXTURE_LOAD_PATH}/public")
151
      middleware.use "ActionDispatch::DebugExceptions"
152 153
      middleware.use "ActionDispatch::Callbacks"
      middleware.use "ActionDispatch::ParamsParser"
J
Joshua Peek 已提交
154
      middleware.use "ActionDispatch::Cookies"
J
Joshua Peek 已提交
155
      middleware.use "ActionDispatch::Flash"
156
      middleware.use "Rack::Head"
157
      yield(middleware) if block_given?
C
Carlhuda 已提交
158
    end
159 160 161 162
  end

  self.app = build_app

163 164 165 166 167 168 169 170 171 172
  # 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
    end

    def dispatch(controller, action, env)
      [200, {'Content-Type' => 'text/html'}, ["#{controller}##{action}"]]
173 174 175 176 177 178 179 180 181 182 183 184 185
    end
  end

  def self.stub_controllers
    old_dispatcher = ActionDispatch::Routing::RouteSet::Dispatcher
    ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher }
    ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, StubDispatcher }
    yield ActionDispatch::Routing::RouteSet.new
  ensure
    ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher }
    ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, old_dispatcher }
  end

186
  def with_routing(&block)
187
    temporary_routes = ActionDispatch::Routing::RouteSet.new
C
Carlhuda 已提交
188 189 190
    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) }
191 192 193

    yield temporary_routes
  ensure
C
Carlhuda 已提交
194 195
    self.class.app = old_app
    silence_warnings { Object.const_set(:SharedTestRoutes, old_routes) }
196
  end
197 198

  def with_autoload_path(path)
199
    path = File.join(File.dirname(__FILE__), "fixtures", path)
200 201 202 203 204 205 206 207 208 209 210 211
    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
212 213
end

J
Joshua Peek 已提交
214
# Temporary base class
215
class Rack::TestCase < ActionDispatch::IntegrationTest
J
Joshua Peek 已提交
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
  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)
233
    assert_equal body, Array(response.body).join
J
Joshua Peek 已提交
234 235 236 237 238 239 240
  end

  def assert_status(code)
    assert_equal code, response.status
  end

  def assert_response(body, status = 200, headers = {})
241
    assert_body body
J
Joshua Peek 已提交
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
    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

257 258
module ActionController
  class Base
259 260
    # This stub emulates the Railtie including the URL helpers from a Rails application
    include SharedTestRoutes.url_helpers
261
    include SharedTestRoutes.mounted_helpers
262

263 264 265 266 267 268 269 270
    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
271

272
  class TestCase
J
Joshua Peek 已提交
273
    include ActionDispatch::TestProcess
274
    include ActionDispatch::SharedRoutes
275 276
  end
end
C
Carlhuda 已提交
277

278

279 280 281
class ::ApplicationController < ActionController::Base
end

A
Aaron Patterson 已提交
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
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
A
Aaron Patterson 已提交
299 300

module ActionDispatch
301 302 303 304 305 306 307
  class DebugExceptions
    private
    remove_method :stderr_logger
    # Silence logger
    def stderr_logger
      nil
    end
A
Aaron Patterson 已提交
308 309 310
  end
end

311 312
module ActionDispatch
  module RoutingVerbs
313
    def send_request(uri_or_host, method, path)
314 315 316 317
      host = uri_or_host.host unless path
      path ||= uri_or_host.path

      params = {'PATH_INFO'      => path,
318
                'REQUEST_METHOD' => method,
319 320
                'HTTP_HOST'      => host}

321 322 323
      routes.call(params)
    end

324 325
    def request_path_params(path, options = {})
      method = options[:method] || 'GET'
326
      resp = send_request URI('http://localhost' + path), method.to_s.upcase, nil
A
Aaron Patterson 已提交
327
      status = resp.first
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
      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
352 353 354 355
    end
  end
end

L
lest 已提交
356
module RoutingTestHelpers
A
Aaron Patterson 已提交
357
  def url_for(set, options)
358 359
    route_name = options.delete :use_route
    set.url_for options.merge(:only_path => true), route_name
L
lest 已提交
360
  end
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402

  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
L
lest 已提交
403
end
404 405 406 407 408 409 410 411 412

class ResourcesController < ActionController::Base
  def index() render :nothing => true end
  alias_method :show, :index
end

class ThreadsController  < ResourcesController; end
class MessagesController < ResourcesController; end
class CommentsController < ResourcesController; end
413
class ReviewsController < ResourcesController; end
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
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
431 432 433 434 435 436 437 438 439

# 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
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490

class ForkingExecutor
  class Server
    include DRb::DRbUndumped

    def initialize
      @queue = Queue.new
    end

    def record reporter, result
      reporter.synchronize { reporter.record result }
    end

    def << 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('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
          queue.record reporter, result
        end
      }
    }
    @size.times { @queue << nil }
    pool.each { |pid| Process.waitpid pid }
  end
end

if ActiveSupport::Testing::Isolation.forking_env?
  # Use N processes (N defaults to 4)
  Minitest.parallel_executor = ForkingExecutor.new((ENV['N'] || 4).to_i)
end