From cc5a957d2b57b1d7081abd6939396f32e7b4b204 Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Mon, 3 Mar 2008 06:42:24 +0000 Subject: Allow file uploads in Integration Tests. Closes #11091 [RubyRedRick] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@8978 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- actionpack/CHANGELOG | 2 + actionpack/lib/action_controller/integration.rb | 50 +++++++++++++++++++++- .../test/controller/integration_upload_test.rb | 47 ++++++++++++++++++++ 3 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 actionpack/test/controller/integration_upload_test.rb (limited to 'actionpack') diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 782e364f7e..58792d9088 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Allow file uploads in Integration Tests. Closes #11091 [RubyRedRick] + * Refactor partial rendering into a PartialTemplate class. [Pratik] * Added that requests with JavaScript as the priority mime type in the accept header and no format extension in the parameters will be treated as though their format was :js when it comes to determining which template to render. This makes it possible for JS requests to automatically render action.js.rjs files without an explicit respond_to block [DHH] diff --git a/actionpack/lib/action_controller/integration.rb b/actionpack/lib/action_controller/integration.rb index d979ca494d..6ccaa7eaa4 100644 --- a/actionpack/lib/action_controller/integration.rb +++ b/actionpack/lib/action_controller/integration.rb @@ -55,6 +55,9 @@ module ActionController # A running counter of the number of requests processed. attr_accessor :request_count + class MultiPartNeededException < Exception + end + # Create and initialize a new +Session+ instance. def initialize reset! @@ -294,6 +297,10 @@ module ActionController parse_result return status + rescue MultiPartNeededException + boundary = "----------XnJLe9ZIbbGUYtzPQJ16u1" + status = process(method, path, multipart_body(parameters, boundary), (headers || {}).merge({"CONTENT_TYPE" => "multipart/form-data; boundary=#{boundary}"})) + return status end # Parses the result of the response and extracts the various values, @@ -342,7 +349,9 @@ module ActionController # Convert the given parameters to a request string. The parameters may # be a string, +nil+, or a Hash. def requestify(parameters, prefix=nil) - if Hash === parameters + if TestUploadedFile === parameters + raise MultiPartNeededException + elsif Hash === parameters return nil if parameters.empty? parameters.map { |k,v| requestify(v, name_with_prefix(prefix, k)) }.join("&") elsif Array === parameters @@ -353,6 +362,45 @@ module ActionController "#{CGI.escape(prefix)}=#{CGI.escape(parameters.to_s)}" end end + + def multipart_requestify(params, first=true) + returning Hash.new do |p| + params.each do |key, value| + k = first ? CGI.escape(key.to_s) : "[#{CGI.escape(key.to_s)}]" + if Hash === value + multipart_requestify(value, false).each do |subkey, subvalue| + p[k + subkey] = subvalue + end + else + p[k] = value + end + end + end + end + + def multipart_body(params, boundary) + multipart_requestify(params).map do |key, value| + if value.respond_to?(:original_filename) + File.open(value.path) do |f| + <<-EOF +--#{boundary}\r +Content-Disposition: form-data; name="#{key}"; filename="#{CGI.escape(value.original_filename)}"\r +Content-Type: #{value.content_type}\r +Content-Length: #{File.stat(value.path).size}\r +\r +#{f.read}\r +EOF + end + else +<<-EOF +--#{boundary}\r +Content-Disposition: form-data; name="#{key}"\r +\r +#{value}\r +EOF + end + end.join("")+"--#{boundary}--\r" + end end # A module used to extend ActionController::Base, so that integration tests diff --git a/actionpack/test/controller/integration_upload_test.rb b/actionpack/test/controller/integration_upload_test.rb new file mode 100644 index 0000000000..0968ae6845 --- /dev/null +++ b/actionpack/test/controller/integration_upload_test.rb @@ -0,0 +1,47 @@ +require 'abstract_unit' +require 'action_controller/integration' +require 'action_controller/routing' + +unless defined? ApplicationController + class ApplicationController < ActionController::Base + end +end + +class UploadTestController < ActionController::Base + session :off + + def update + SessionUploadTest.last_request_type = ActionController::Base.param_parsers[request.content_type] + render :text => "got here" + end +end + +class SessionUploadTest < ActionController::IntegrationTest + FILES_DIR = File.dirname(__FILE__) + '/../fixtures/multipart' + + class << self + attr_accessor :last_request_type + end + + + # def setup + # @session = ActionController::Integration::Session.new + # end + # + def test_post_with_upload + uses_mocha "test_post_with_upload" do + Dependencies.stubs(:load?).returns(false) + with_routing do |set| + set.draw do |map| + map.update 'update', :controller => "upload_test", :action => "update", :method => :post + end + path = "/update" + params = {:uploaded_data => fixture_file_upload(FILES_DIR + "/mona_lisa.jpg", "image/jpg")} + headers = {:location => 'blah' } + post(path,params,headers) + assert_equal(:multipart_form, SessionUploadTest.last_request_type) + end + end + + end +end \ No newline at end of file -- cgit v1.2.3