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

Object#stub fails with certain final arguments #918

Closed
tsugimoto opened this issue Jun 24, 2022 · 8 comments
Closed

Object#stub fails with certain final arguments #918

tsugimoto opened this issue Jun 24, 2022 · 8 comments
Assignees

Comments

@tsugimoto
Copy link

From Minitest 5.16.0, the last argument of the stubbed method should not be certain kind of objects, unpermitted ActionController::Parameters in particular, because Ruby 2.7 tries to convert them into kwargs with #to_h and raises.

ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
from /usr/local/bundle/gems/actionpack-6.1.6/lib/action_controller/metal/strong_parameters.rb:316:in `to_h'

For example, the method Auth::Token::create_or_retry

class Auth::Token < ApplicationRecord
  def self.create_with_retry(user, raw_params, limit: 3)
    # actually create a token with retry, and record generic information from raw_params
  end
end

with this usage

class Auth::TokensController < ApplicationController
  def create
    device = Auth::Token.create_with_retry(current_user, params)
  end
end

couldn't be stubbed with any of these in Ruby 2.7 (some of them work in Ruby 3.0+)

Auth::Token.stub(:create_with_retry, ->(_user, _raw_params)
Auth::Token.stub(:create_with_retry, ->(_user, _raw_params, limit:)
Auth::Token.stub(:create_with_retry, ->(_user, _raw_params, **kwargs)

Filed from #912 (comment)

@zenspider
Copy link
Collaborator

I can't reproduce. This is what I currently have:

#!/usr/bin/env ruby -w

require "minitest/mock"

class T
  def self.create_with_retry(user, raw_params, limit: 3)
    raise "shouldn't see this"
  end
end

class C
  def create current_user, params
    T.create_with_retry(current_user, params)
  end
end

class P
  def inspect; "<params>"; end
  def to_hash; { limit: 42 }; end
end

# this is the code run during all 3 stubs, it has a "P"arams as last arg
body = proc { C.new.create :user, P.new }

callable1 = ->(_user, _raw_params)              { 42 }
callable2 = ->(_user, _raw_params, limit:false) { 42 } # had to add false
callable3 = ->(_user, _raw_params, **kwargs)    { 42 }

T.stub(:create_with_retry, callable1, :user, P.new, &body)
T.stub(:create_with_retry, callable2, :user, P.new, &body)
T.stub(:create_with_retry, callable3, :user, P.new, &body)

# Passed: 2.6.10, 2.7.6, 3.0.4, 3.1.2

@zenspider zenspider self-assigned this Jun 25, 2022
@zenspider
Copy link
Collaborator

OK. Cluing in. I needed the to_hash to raise to emulate unpermitted params... This is a version with ALL the hacks in it needed to make it run. Still poking now that I better understand:

#!/usr/bin/env ruby -w

require "minitest/mock"

class T
  def self.create_with_retry(user, raw_params)
    raise "shouldn't see this"
  end
end

class C
  def create current_user, params
    T.create_with_retry current_user, params, **{}
  end
end

class P
  def inspect; "<params>"; end
  def to_hash; raise "nah"; end
end

# this is the code run during all 3 stubs, it has a "P"arams as last arg
# NOTE: this has a forced kwargs kludge in it: **{} to prevent #to_hash
body = proc { C.new.create :user, P.new, **{} }

callable1 = ->(_user, _raw_params)              { 42 }
callable2 = ->(_user, _raw_params, limit:false) { 42 } # had to add false
callable3 = ->(_user, _raw_params, **kwargs)    { 42 }

p T.stub(:create_with_retry, callable1, &body)
p T.stub(:create_with_retry, callable2, &body)
p T.stub(:create_with_retry, callable3, &body)

@zenspider
Copy link
Collaborator

OK. I believe I have this fixed to work without the **{} hacks from above. You need to define MT_KWARGS_HACK=1 in your environment to get it to work.

@zenspider
Copy link
Collaborator

This is released in 5.16.2. Thanks for reporting! Please verify and close if this fixes your issues.

@whisper-ah
Copy link

We had a similar issue with mocked and stubbed tests when upgrading from Rails 5.2 to 6.1 using Ruby 2.7

This did fix our failures, thanks @zenspider 🥰

pboling added a commit to oauth-xx/oauth-ruby that referenced this issue Aug 23, 2022
@blowmage
Copy link

@tsugimoto does 5.16.2 and MT_KWARGS_HACK=1 resolve your stub failures? can this issue be closed?

@ahangarha
Copy link

@blowmage
MT_KWARGS_HACK=1 resolved the same problem I had.

I think this issue can get closed

@tsugimoto
Copy link
Author

Confirmed with minitest 5.16.2 and MT_KWARGS_HACK=1.
Thank you!

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

No branches or pull requests

5 participants