Navigation Menu

Skip to content

Commit

Permalink
rack-test 0.4.2 has rack 1.1.pre goodies, we'll use it instead
Browse files Browse the repository at this point in the history
  • Loading branch information
josh committed Sep 1, 2009
1 parent 426e76a commit a79790e
Show file tree
Hide file tree
Showing 5 changed files with 13 additions and 311 deletions.
14 changes: 6 additions & 8 deletions actionpack/lib/action_controller/testing/integration.rb
Expand Up @@ -2,9 +2,7 @@
require 'uri'
require 'active_support/test_case'
require 'active_support/core_ext/object/metaclass'

require 'rack/mock_session'
require 'rack/test/cookie_jar'
require 'rack/test'

module ActionController
module Integration #:nodoc:
Expand Down Expand Up @@ -251,7 +249,7 @@ def process(method, path, parameters = nil, rack_environment = nil)
end
end

opts = {
env = {
:method => method,
:params => parameters,

Expand All @@ -268,18 +266,18 @@ def process(method, path, parameters = nil, rack_environment = nil)
"HTTP_ACCEPT" => accept
}

env = ActionDispatch::TestRequest.env_for(path, opts)

(rack_environment || {}).each do |key, value|
env[key] = value
end

session = Rack::Test::Session.new(@mock_session)

@controller = ActionController::Base.capture_instantiation do
@mock_session.request(URI.parse(path), env)
session.request(path, env)
end

@request_count += 1
@request = ActionDispatch::Request.new(env)
@request = ActionDispatch::Request.new(session.last_request.env)
@response = ActionDispatch::TestResponse.from_response(@mock_session.last_response)
@html_document = nil

Expand Down
2 changes: 1 addition & 1 deletion actionpack/lib/action_controller/testing/process.rb
Expand Up @@ -84,7 +84,7 @@ def initialize(session = {})
#
# Pass a true third parameter to ensure the uploaded file is opened in binary mode (only required for Windows):
# post :change_avatar, :avatar => ActionController::TestUploadedFile.new(ActionController::TestCase.fixture_path + '/files/spongebob.png', 'image/png', :binary)
TestUploadedFile = ActionDispatch::TestRequest::Multipart::UploadedFile
TestUploadedFile = Rack::Test::UploadedFile

module TestProcess
def self.included(base)
Expand Down
299 changes: 2 additions & 297 deletions actionpack/lib/action_dispatch/testing/test_request.rb
@@ -1,308 +1,13 @@
module ActionDispatch
class TestRequest < Request
# Improve version of Multipart thats in rack/master
module Multipart #:nodoc:
class UploadedFile
# The filename, *not* including the path, of the "uploaded" file
attr_reader :original_filename

# The content type of the "uploaded" file
attr_accessor :content_type

def initialize(path, content_type = "text/plain", binary = false)
raise "#{path} file does not exist" unless ::File.exist?(path)
@content_type = content_type
@original_filename = ::File.basename(path)
@tempfile = Tempfile.new(@original_filename)
@tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding)
@tempfile.binmode if binary
FileUtils.copy_file(path, @tempfile.path)
end

def path
@tempfile.path
end
alias_method :local_path, :path

def method_missing(method_name, *args, &block) #:nodoc:
@tempfile.__send__(method_name, *args, &block)
end
end

EOL = "\r\n"
MULTIPART_BOUNDARY = "AaB03x"

def self.parse_multipart(env)
unless env['CONTENT_TYPE'] =~
%r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n
nil
else
boundary = "--#{$1}"

params = {}
buf = ""
content_length = env['CONTENT_LENGTH'].to_i
input = env['rack.input']
input.rewind

boundary_size = Utils.bytesize(boundary) + EOL.size
bufsize = 16384

content_length -= boundary_size

read_buffer = ''

status = input.read(boundary_size, read_buffer)
raise EOFError, "bad content body" unless status == boundary + EOL

rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n

loop {
head = nil
body = ''
filename = content_type = name = nil

until head && buf =~ rx
if !head && i = buf.index(EOL+EOL)
head = buf.slice!(0, i+2) # First \r\n
buf.slice!(0, 2) # Second \r\n

filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1]
content_type = head[/Content-Type: (.*)#{EOL}/ni, 1]
name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1]

if content_type || filename
body = Tempfile.new("RackMultipart")
body.binmode if body.respond_to?(:binmode)
end

next
end

# Save the read body part.
if head && (boundary_size+4 < buf.size)
body << buf.slice!(0, buf.size - (boundary_size+4))
end

c = input.read(bufsize < content_length ? bufsize : content_length, read_buffer)
raise EOFError, "bad content body" if c.nil? || c.empty?
buf << c
content_length -= c.size
end

# Save the rest.
if i = buf.index(rx)
body << buf.slice!(0, i)
buf.slice!(0, boundary_size+2)

content_length = -1 if $1 == "--"
end

if filename == ""
# filename is blank which means no file has been selected
data = nil
elsif filename
body.rewind

# Take the basename of the upload's original filename.
# This handles the full Windows paths given by Internet Explorer
# (and perhaps other broken user agents) without affecting
# those which give the lone filename.
filename =~ /^(?:.*[:\\\/])?(.*)/m
filename = $1

data = {:filename => filename, :type => content_type,
:name => name, :tempfile => body, :head => head}
elsif !filename && content_type
body.rewind

# Generic multipart cases, not coming from a form
data = {:type => content_type,
:name => name, :tempfile => body, :head => head}
else
data = body
end

Utils.normalize_params(params, name, data) unless data.nil?

break if buf.empty? || content_length == -1
}

input.rewind

params
end
end

def self.build_multipart(params, first = true)
if first
unless params.is_a?(Hash)
raise ArgumentError, "value must be a Hash"
end

multipart = false
query = lambda { |value|
case value
when Array
value.each(&query)
when Hash
value.values.each(&query)
when UploadedFile
multipart = true
end
}
params.values.each(&query)
return nil unless multipart
end

flattened_params = Hash.new

params.each do |key, value|
k = first ? key.to_s : "[#{key}]"

case value
when Array
value.map { |v|
build_multipart(v, false).each { |subkey, subvalue|
flattened_params["#{k}[]#{subkey}"] = subvalue
}
}
when Hash
build_multipart(value, false).each { |subkey, subvalue|
flattened_params[k + subkey] = subvalue
}
else
flattened_params[k] = value
end
end

if first
flattened_params.map { |name, file|
if file.respond_to?(:original_filename)
::File.open(file.path, "rb") do |f|
f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding)
<<-EOF
--#{MULTIPART_BOUNDARY}\r
Content-Disposition: form-data; name="#{name}"; filename="#{Rack::Utils.escape(file.original_filename)}"\r
Content-Type: #{file.content_type}\r
Content-Length: #{::File.stat(file.path).size}\r
\r
#{f.read}\r
EOF
end
else
<<-EOF
--#{MULTIPART_BOUNDARY}\r
Content-Disposition: form-data; name="#{name}"\r
\r
#{file}\r
EOF
end
}.join + "--#{MULTIPART_BOUNDARY}--\r"
else
flattened_params
end
end
end

DEFAULT_ENV = {
"rack.version" => [1,0],
"rack.input" => StringIO.new,
"rack.errors" => StringIO.new,
"rack.multithread" => true,
"rack.multiprocess" => true,
"rack.run_once" => false,
}

# Improve version of env_for thats in rack/master
def self.env_for(uri="", opts={}) #:nodoc:
uri = URI(uri)
uri.path = "/#{uri.path}" unless uri.path[0] == ?/

env = DEFAULT_ENV.dup

env["REQUEST_METHOD"] = opts[:method] ? opts[:method].to_s.upcase : "GET"
env["SERVER_NAME"] = uri.host || "example.org"
env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80"
env["QUERY_STRING"] = uri.query.to_s
env["PATH_INFO"] = (!uri.path || uri.path.empty?) ? "/" : uri.path
env["rack.url_scheme"] = uri.scheme || "http"
env["HTTPS"] = env["rack.url_scheme"] == "https" ? "on" : "off"

env["SCRIPT_NAME"] = opts[:script_name] || ""

if opts[:fatal]
env["rack.errors"] = FatalWarner.new
else
env["rack.errors"] = StringIO.new
end

if params = opts[:params]
if env["REQUEST_METHOD"] == "GET"
params = Rack::Utils.parse_nested_query(params) if params.is_a?(String)
params.update(Rack::Utils.parse_nested_query(env["QUERY_STRING"]))
env["QUERY_STRING"] = build_nested_query(params)
elsif !opts.has_key?(:input)
opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded"
if params.is_a?(Hash)
if data = Multipart.build_multipart(params)
opts[:input] = data
opts["CONTENT_LENGTH"] ||= data.length.to_s
opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Multipart::MULTIPART_BOUNDARY}"
else
opts[:input] = build_nested_query(params)
end
else
opts[:input] = params
end
end
end

empty_str = ""
empty_str.force_encoding("ASCII-8BIT") if empty_str.respond_to? :force_encoding
opts[:input] ||= empty_str
if String === opts[:input]
rack_input = StringIO.new(opts[:input])
else
rack_input = opts[:input]
end

rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
env['rack.input'] = rack_input

env["CONTENT_LENGTH"] ||= env["rack.input"].length.to_s

opts.each { |field, value|
env[field] = value if String === field
}

env
end

def self.build_nested_query(value, prefix = nil)
case value
when Array
value.map { |v|
build_nested_query(v, "#{prefix}[]")
}.join("&")
when Hash
value.map { |k, v|
build_nested_query(v, prefix ? "#{prefix}[#{Rack::Utils.escape(k)}]" : Rack::Utils.escape(k))
}.join("&")
when String
raise ArgumentError, "value must be a Hash" if prefix.nil?
"#{prefix}=#{Rack::Utils.escape(value)}"
else
prefix
end
end
DEFAULT_ENV = Rack::MockRequest.env_for('/')

def self.new(env = {})
super
end

def initialize(env = {})
super(self.class.env_for('/').merge(env))
super(DEFAULT_ENV.merge(env))

self.host = 'test.host'
self.remote_addr = '0.0.0.0'
Expand Down
4 changes: 2 additions & 2 deletions actionpack/test/dispatch/test_request_test.rb
Expand Up @@ -5,7 +5,7 @@ class TestRequestTest < ActiveSupport::TestCase
env = ActionDispatch::TestRequest.new.env

assert_equal "GET", env.delete("REQUEST_METHOD")
assert_equal "off", env.delete("HTTPS")
assert_equal nil, env.delete("HTTPS")
assert_equal "http", env.delete("rack.url_scheme")
assert_equal "example.org", env.delete("SERVER_NAME")
assert_equal "80", env.delete("SERVER_PORT")
Expand All @@ -18,7 +18,7 @@ class TestRequestTest < ActiveSupport::TestCase
assert_equal "0.0.0.0", env.delete("REMOTE_ADDR")
assert_equal "Rails Testing", env.delete("HTTP_USER_AGENT")

assert_equal [1, 0], env.delete("rack.version")
assert_equal [0, 1], env.delete("rack.version")
assert_equal "", env.delete("rack.input").string
assert_kind_of StringIO, env.delete("rack.errors")
assert_equal true, env.delete("rack.multithread")
Expand Down
5 changes: 2 additions & 3 deletions ci/geminstaller.yml
Expand Up @@ -15,9 +15,8 @@ gems:
version: >= 0.8.0
- name: rack
version: '~> 1.0.0'
- name: josh-rack-test
version: >= 0.4.1
install_options: --source=http://gems.github.com
- name: rack-test
version: >= 0.4.2
- name: rake
version: >= 0.8.1
- name: sqlite-ruby
Expand Down

0 comments on commit a79790e

Please sign in to comment.