Permalink
Browse files

Make integration test runner more Rack friendly and clean out old CGI…

… cruft
  • Loading branch information...
1 parent e4eadf3 commit ebec9d43e262d28d742ff10acd828bad6cbb28ed @josh josh committed Dec 7, 2008
@@ -9,13 +9,17 @@ module Integration #:nodoc:
# multiple sessions and run them side-by-side, you can also mimic (to some
# limited extent) multiple simultaneous users interacting with your system.
#
- # Typically, you will instantiate a new session using IntegrationTest#open_session,
- # rather than instantiating Integration::Session directly.
+ # Typically, you will instantiate a new session using
+ # IntegrationTest#open_session, rather than instantiating
+ # Integration::Session directly.
class Session
include Test::Unit::Assertions
include ActionController::TestCase::Assertions
include ActionController::TestProcess
+ # Rack application to use
+ attr_accessor :application
+
# The integer HTTP status code of the last request.
attr_reader :status
@@ -57,7 +61,8 @@ class MultiPartNeededException < Exception
end
# Create and initialize a new Session instance.
- def initialize
+ def initialize(app)
+ @application = app
reset!
end
@@ -76,11 +81,13 @@ def reset!
self.host = "www.example.com"
self.remote_addr = "127.0.0.1"
- self.accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"
+ self.accept = "text/xml,application/xml,application/xhtml+xml," +
+ "text/html;q=0.9,text/plain;q=0.8,image/png," +
+ "*/*;q=0.5"
unless defined? @named_routes_configured
# install the named routes in this session instance.
- klass = class<<self; self; end
+ klass = class << self; self; end
Routing::Routes.install_helpers(klass)
# the helpers are made protected by default--we make them public for
@@ -94,7 +101,7 @@ def reset!
#
# session.https!
# session.https!(false)
- def https!(flag=true)
+ def https!(flag = true)
@https = flag
end
@@ -164,40 +171,48 @@ def redirect?
# Performs a GET request with the given parameters.
#
- # - +path+: The URI (as a String) on which you want to perform a GET request.
- # - +parameters+: The HTTP parameters that you want to pass. This may be +nil+,
+ # - +path+: The URI (as a String) on which you want to perform a GET
+ # request.
+ # - +parameters+: The HTTP parameters that you want to pass. This may
+ # be +nil+,
# a Hash, or a String that is appropriately encoded
- # (<tt>application/x-www-form-urlencoded</tt> or <tt>multipart/form-data</tt>).
+ # (<tt>application/x-www-form-urlencoded</tt> or
+ # <tt>multipart/form-data</tt>).
# - +headers+: Additional HTTP headers to pass, as a Hash. The keys will
# automatically be upcased, with the prefix 'HTTP_' added if needed.
#
- # This method returns an AbstractResponse object, which one can use to inspect
- # the details of the response. Furthermore, if this method was called from an
- # ActionController::IntegrationTest object, then that object's <tt>@response</tt>
- # instance variable will point to the same response object.
+ # This method returns an AbstractResponse object, which one can use to
+ # inspect the details of the response. Furthermore, if this method was
+ # called from an ActionController::IntegrationTest object, then that
+ # object's <tt>@response</tt> instance variable will point to the same
+ # response object.
#
# You can also perform POST, PUT, DELETE, and HEAD requests with +post+,
# +put+, +delete+, and +head+.
def get(path, parameters = nil, headers = nil)
process :get, path, parameters, headers
end
- # Performs a POST request with the given parameters. See get() for more details.
+ # Performs a POST request with the given parameters. See get() for more
+ # details.
def post(path, parameters = nil, headers = nil)
process :post, path, parameters, headers
end
- # Performs a PUT request with the given parameters. See get() for more details.
+ # Performs a PUT request with the given parameters. See get() for more
+ # details.
def put(path, parameters = nil, headers = nil)
process :put, path, parameters, headers
end
- # Performs a DELETE request with the given parameters. See get() for more details.
+ # Performs a DELETE request with the given parameters. See get() for
+ # more details.
def delete(path, parameters = nil, headers = nil)
process :delete, path, parameters, headers
end
- # Performs a HEAD request with the given parameters. See get() for more details.
+ # Performs a HEAD request with the given parameters. See get() for more
+ # details.
def head(path, parameters = nil, headers = nil)
process :head, path, parameters, headers
end
@@ -212,7 +227,8 @@ def head(path, parameters = nil, headers = nil)
def xml_http_request(request_method, path, parameters = nil, headers = nil)
headers ||= {}
headers['X-Requested-With'] = 'XMLHttpRequest'
- headers['Accept'] ||= 'text/javascript, text/html, application/xml, text/xml, */*'
+ headers['Accept'] ||= 'text/javascript, text/html, application/xml, ' +
+ 'text/xml, */*'
process(request_method, path, parameters, headers)
end
@@ -221,7 +237,9 @@ def xml_http_request(request_method, path, parameters = nil, headers = nil)
# Returns the URL for the given options, according to the rules specified
# in the application's routes.
def url_for(options)
- controller ? controller.url_for(options) : generic_url_rewriter.rewrite(options)
+ controller ?
+ controller.url_for(options) :
+ generic_url_rewriter.rewrite(options)
end
private
@@ -247,17 +265,33 @@ def process(method, path, parameters = nil, headers = nil)
data = nil
end
+ env["QUERY_STRING"] ||= ""
+
+ data = data.is_a?(IO) ? data : StringIO.new(data || '')
+
env.update(
- "REQUEST_METHOD" => method.to_s.upcase,
+ "REQUEST_METHOD" => method.to_s.upcase,
+ "SERVER_NAME" => host,
+ "SERVER_PORT" => (https? ? "443" : "80"),
+ "HTTPS" => https? ? "on" : "off",
+ "rack.url_scheme" => https? ? "https" : "http",
+ "SCRIPT_NAME" => "",
+
"REQUEST_URI" => path,
"HTTP_HOST" => host,
"REMOTE_ADDR" => remote_addr,
- "SERVER_PORT" => (https? ? "443" : "80"),
"CONTENT_TYPE" => "application/x-www-form-urlencoded",
"CONTENT_LENGTH" => data ? data.length.to_s : nil,
"HTTP_COOKIE" => encode_cookies,
- "HTTPS" => https? ? "on" : "off",
"HTTP_ACCEPT" => accept,
+
+ "rack.version" => [0,1],
+ "rack.input" => data,
+ "rack.errors" => StringIO.new,
+ "rack.multithread" => true,
+ "rack.multiprocess" => true,
+ "rack.run_once" => false,
+
"action_controller.test" => true
)
@@ -273,48 +307,43 @@ def process(method, path, parameters = nil, headers = nil)
ActionController::Base.clear_last_instantiation!
- env['rack.input'] = data.is_a?(IO) ? data : StringIO.new(data || '')
- @status, @headers, result_body = ActionController::Dispatcher.new.call(env)
+ app = Rack::Lint.new(@application)
+
+ status, headers, body = app.call(env)
@request_count += 1
- @controller = ActionController::Base.last_instantiation
- @request = @controller.request
- @response = @controller.response
+ if @controller = ActionController::Base.last_instantiation
+ @request = @controller.request
+ @response = @controller.response
- # Decorate the response with the standard behavior of the TestResponse
- # so that things like assert_response can be used in integration
- # tests.
- @response.extend(TestResponseBehavior)
+ # Decorate the response with the standard behavior of the
+ # TestResponse so that things like assert_response can be
+ # used in integration tests.
+ @response.extend(TestResponseBehavior)
+ end
@html_document = nil
- # Inject status back in for backwords compatibility with CGI
- @headers['Status'] = @status
-
- @status, @status_message = @status.split(/ /)
- @status = @status.to_i
+ @status = status.to_i
+ @status_message = StatusCodes::STATUS_CODES[@status]
- cgi_headers = Hash.new { |h,k| h[k] = [] }
- @headers.each do |key, value|
- cgi_headers[key.downcase] << value
- end
- cgi_headers['set-cookie'] = cgi_headers['set-cookie'].first
- @headers = cgi_headers
+ @headers = Rack::Utils::HeaderHash.new(headers)
- @response.headers['cookie'] ||= []
- (@headers['set-cookie'] || []).each do |cookie|
+ (@headers['Set-Cookie'] || []).each do |cookie|
name, value = cookie.match(/^([^=]*)=([^;]*);/)[1,2]
@cookies[name] = value
-
- # Fake CGI cookie header
- # DEPRECATE: Use response.headers["Set-Cookie"] instead
- @response.headers['cookie'] << CGI::Cookie::new("name" => name, "value" => value)
end
- return status
+ @body = ""
+ body.each { |part| @body << part }
+
+ return @status
rescue MultiPartNeededException
boundary = "----------XnJLe9ZIbbGUYtzPQJ16u1"
- status = process(method, path, multipart_body(parameters, boundary), (headers || {}).merge({"CONTENT_TYPE" => "multipart/form-data; boundary=#{boundary}"}))
+ status = process(method, path,
+ multipart_body(parameters, boundary),
+ (headers || {}).merge(
+ {"CONTENT_TYPE" => "multipart/form-data; boundary=#{boundary}"}))
return status
end
@@ -336,7 +365,7 @@ def generic_url_rewriter
"SERVER_PORT" => https? ? "443" : "80",
"HTTPS" => https? ? "on" : "off"
}
- ActionController::UrlRewriter.new(ActionController::RackRequest.new(env), {})
+ UrlRewriter.new(RackRequest.new(env), {})
end
def name_with_prefix(prefix, name)
@@ -350,9 +379,13 @@ def requestify(parameters, prefix=nil)
raise MultiPartNeededException
elsif Hash === parameters
return nil if parameters.empty?
- parameters.map { |k,v| requestify(v, name_with_prefix(prefix, k)) }.join("&")
+ parameters.map { |k,v|
+ requestify(v, name_with_prefix(prefix, k))
+ }.join("&")
elsif Array === parameters
- parameters.map { |v| requestify(v, name_with_prefix(prefix, "")) }.join("&")
+ parameters.map { |v|
+ requestify(v, name_with_prefix(prefix, ""))
+ }.join("&")
elsif prefix.nil?
parameters
else
@@ -459,20 +492,25 @@ def reset!
# can use this method to open multiple sessions that ought to be tested
# simultaneously.
def open_session
- session = Integration::Session.new
+ application = ActionController::Dispatcher.new
+ session = Integration::Session.new(application)
# delegate the fixture accessors back to the test instance
extras = Module.new { attr_accessor :delegate, :test_result }
if self.class.respond_to?(:fixture_table_names)
self.class.fixture_table_names.each do |table_name|
name = table_name.tr(".", "_")
next unless respond_to?(name)
- extras.__send__(:define_method, name) { |*args| delegate.send(name, *args) }
+ extras.__send__(:define_method, name) { |*args|
+ delegate.send(name, *args)
+ }
end
end
# delegate add_assertion to the test case
- extras.__send__(:define_method, :add_assertion) { test_result.add_assertion }
+ extras.__send__(:define_method, :add_assertion) {
+ test_result.add_assertion
+ }
session.extend(extras)
session.delegate = self
session.test_result = @_result
@@ -600,7 +638,8 @@ def run(*args) #:nodoc:
# would potentially have to set their values for both Test::Unit::TestCase
# ActionController::IntegrationTest, since by the time the value is set on
# TestCase, IntegrationTest has already been defined and cannot inherit
- # changes to those variables. So, we make those two attributes copy-on-write.
+ # changes to those variables. So, we make those two attributes
+ # copy-on-write.
class << self
def use_transactional_fixtures=(flag) #:nodoc:
@@ -55,14 +55,7 @@ def key?(key)
end
def cookies
- return {} unless @env["HTTP_COOKIE"]
-
- unless @env["rack.request.cookie_string"] == @env["HTTP_COOKIE"]
- @env["rack.request.cookie_string"] = @env["HTTP_COOKIE"]
- @env["rack.request.cookie_hash"] = CGI::Cookie::parse(@env["rack.request.cookie_string"])
- end
-
- @env["rack.request.cookie_hash"]
+ Rack::Request.new(@env).cookies
end
def server_port
Oops, something went wrong.

0 comments on commit ebec9d4

Please sign in to comment.