How to fake file upload when checking Ruby Rack serverless?
For testing purposes, I am sending the Rack :: Request directly to the application, without using a server.
def request_via_API( app, method, path, params={} ) # app should be API
env = Rack::MockRequest.env_for( path, {:method => method, :params=>params} )
app.handle Rack::Request.new(env)
end
works fine for testing direct input, but file upload drowns me. My real system works fine with a file upload browser. But now I want to test it using the API and don't know how to get the file content in the request via any of the Rack classes / methods. (I tried to understand Rack :: Test :: UploadedFile but failed).
Thanks Alistair
source to share
You were definitely on the right track. You can even use your function request_via_API
without any changes, for example:
request_via_API(app, 'POST', '/', {
:field => "value",
:text_source => Rack::Multipart::UploadedFile.new(PATH_TO_YOUR_FILE, MIME_TYPE_OF_YOUR_FILE)
})
This means that you must have a file of some kind. If you are using fixtures, your test boot file should be around them. You can omit the MIME time, but the default is text/plain
.
If you are using barebones Rack you get the following hash after the call Rack::Multipart.parse_multipart
:
{
"field" => "value",
"text_source" => {
:filename => File.basename(PATH_TO_YOUR_FILE),
:type => MIME_TYPE_OF_YOUR_FILE,
:name => "text_source",
:tempfile => Tempfile.new("RackMultipart"), # copied from PATH_TO_YOUR_FILE
:head => "Content-Disposition: form-data; name=\"text_source\"; filename=\"#{File.basename(PATH_TO_YOUR_FILE)}\"\r\n" +
"Content-Type: #{MIME_TYPE_OF_YOUR_FILE}\r\n" +
"Content-Length: #{BYTESIZE_OF_YOUR_FILE}\r\n"
}
}
The key text_source
can have any other name, of course.
Rack::MockRequest#env_for
automatically tries to create a data query with multiple data if:
- HTTP method not GET
- missing option
:input
-
:params
- this isHash
-
:params
parameter values contain at least one instanceRack::Multipart::UploadedFile
You can see the details in the source code here and here .
I think relying on generating multiple requests for Rack::MockRequest
and Rack::Multipart
only useful for mocking HTML forms with file uploads and file upload mechanisms that act the same. Thus, there is no need to directly use Rack::Multipart#build_multipart
or Rack::Multipart::Generator
.
If you have more complex multi-page scripts or another file upload mechanism, you must pass the argument as a opts
key :input
instead of :params
on . How you create this value for is your problem as it is about related Rack capabilities. It only wraps it in , if that 's how you can see. Otherwise, it is the same as what would be passed as in the hash environment of the Rack environment, and therefore must conform to the Rack input stream specification (i.e., be a -like object). Rack::MockRequest#env_for
:input
StringIO
String
rack.input
IO
Because it was quite a challenge for me and I used it as an exercise to deepen my knowledge of Rack I by creating a simple project on GitHub to explore this file by uploading a mock.
Note. I tried to fix everything in Rack 1.5.2 except for the Rack SPEC reference (so be careful). The Ruby StdLib references lead to the current version.
source to share