Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ability to create Test::UploadedFile instances without the file system #149

Merged
merged 3 commits into from
Jul 18, 2017

Conversation

amilligan
Copy link
Contributor

Uploaded files behave as IO streams, so it should be reasonable to instantiate a fake one from an IO stream. These changes don't change the existing interface to the #initialize method, but add the ability to do something like this:

io = StringIO.new('Some content')
upload = Rack::Test::UploadedFile.new(io, original_filename: 'wibble.txt')
...

A lot of tests for content uploads don't need a lot of complex content; this should allow for test suites without a bunch of tiny test files cluttering the project or spec directories.

@dennissivia
Copy link

Thanks for the contribution. I really like the idea, but I am not to sure about all details of the implementation. Especially the conditional switch on respond_to to then handle IO object and paths differently.
However I don't want to to reject anything for that reason. What do you think @perlun and @junaruga

@junaruga
Copy link
Contributor

junaruga commented May 3, 2017

@scepticulous I like the idea too, though I have not checked the actual source code yet.
Thanks for the contribution.

@perlun
Copy link
Contributor

perlun commented May 22, 2017

@amilligan This has now conflicts with the current master code. Are you still around, and if so, could you try to rebase this on top of the current tree?

@amilligan
Copy link
Contributor Author

Okay, I fixed the conflicts; nothing too concerning.

Regarding an earlier concern: I don't like using #respond_to? in almost any circumstances, but in this case the existing initializer interface expects a filename as a string, which is not easily reconciled with also accepting an abstract IO stream. Ideally, the initializer would accept only an IO stream, but that would break the existing interface.

I can think of any number of ways to work around this, but #respond_to? seems to be the most generally accepted in the Ruby community. I'm open to suggestions, if you have preferences.

@perlun
Copy link
Contributor

perlun commented Jul 14, 2017

@amilligan this now has conflicts again. 😄 If you rebase one more time, I promise we'll try to give it a look.

Adam Milligan added 3 commits July 16, 2017 18:04
The initializer now accepts an IO object, which allows callers to
instantiate fake upload objects with in-memory content.
@amilligan
Copy link
Contributor Author

Resolved again; ready for a look.

Copy link
Contributor

@perlun perlun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One question that I think should be resolved before merge, but in general - thanks! A valuable contribution. @scepticulous and @junaruga, feel free to chime in as well.

def respond_to?(method_name, include_private = false) #:nodoc:
@tempfile.respond_to?(method_name, include_private) || super
def respond_to_missing?(method_name, include_private = false) #:nodoc:
tempfile.respond_to?(method_name, include_private) || super
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://ruby-doc.org/core-2.4.1/Object.html#method-i-respond_to_missing-3F says:

DO NOT USE THIS DIRECTLY.

Is there a way to implement this in another way?

@junaruga
Copy link
Contributor

Yeah, sure.

@amilligan
Copy link
Contributor Author

@perlun I'm slightly confused. You're asking about the choice to implement #respond_to_missing? as opposed to #respond_to??

As of ruby 1.9 implementing the former is the invariably preferred mechanism. The 'DO NOT USE THIS DIRECTLY' directive refers to calling the method, which I don't believe is done anywhere in the project.

@perlun
Copy link
Contributor

perlun commented Jul 18, 2017

@perlun I'm slightly confused. You're asking about the choice to implement #respond_to_missing? as opposed to #respond_to??

As of ruby 1.9 implementing the former is the invariably preferred mechanism. The 'DO NOT USE THIS DIRECTLY' directive refers to calling the method, which I don't believe is done anywhere in the project.

I stand corrected. 🙈 Sorry for that @amilligan! This blog post explains some more of the details.

I am fine with this now. Will approve and merge. Thanks for the effort, and sorry about the delay!

@perlun perlun merged commit 5fd3631 into rack:master Jul 18, 2017
@tagliala
Copy link

Hi,

This change is breaking an use case in specs with Paperclip + FactoryBot.

The suggested method documented here: https://github.com/thoughtbot/paperclip#testing

FactoryGirl.define do
  factory :user do
    avatar { File.new("#{Rails.root}/spec/support/fixtures/image.jpg") }
  end
end

does not work anymore:

     NoMethodError:
       undefined method `size' for nil:NilClass
     # ~/dev/rack-test/lib/rack/test/uploaded_file.rb:38:in `public_send'
     # ~/dev/rack-test/lib/rack/test/uploaded_file.rb:38:in `method_missing'
     # ~/dev/rack-test/lib/rack/test/utils.rb:136:in `build_file_part'
     # ~/dev/rack-test/lib/rack/test/utils.rb:101:in `block in get_parts'
     # ~/dev/rack-test/lib/rack/test/utils.rb:92:in `each'
     # ~/dev/rack-test/lib/rack/test/utils.rb:92:in `map'
     # ~/dev/rack-test/lib/rack/test/utils.rb:92:in `get_parts'
     # ~/dev/rack-test/lib/rack/test/utils.rb:87:in `build_parts'
     # ~/dev/rack-test/lib/rack/test/utils.rb:77:in `build_multipart'
     # ~/dev/rack-test/lib/rack/test.rb:231:in `env_for'
     # ~/dev/rack-test/lib/rack/test.rb:128:in `custom_request'
     # ~/dev/rack-test/lib/rack/test.rb:66:in `post'

Is there any suggested way of doing this with rack-test 0.7.1? Should I report this to Paperclip?

I've tried several things but I'm unable to make it work.

TIA

@007lva
Copy link

007lva commented Nov 20, 2017

Hi,

I have the same problem with 0.7.1: rspec/rspec-rails#1915

@perlun
Copy link
Contributor

perlun commented Nov 20, 2017

@tagliala @007lva Sorry for this; this is an unintended regression because of this change. For now, downgrade your project to 0.7.0 to work around the issue.

If either one of you could provide a PR with a failing test case to the rack-test repo, that would be 👍 👍 👍. We will then try to fix this as soon as possible, and get a fixed gem version released.

I will lock this conversation now, since it's too hard to find discussions going on in "merged pull requests"; we need it in a new issue or PR for it to be visible to the audience at large.

@rack rack locked and limited conversation to collaborators Nov 20, 2017
@perlun
Copy link
Contributor

perlun commented Dec 27, 2017

The issue @tagliala reported is now here: #214

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants