oesmith / puffing-billy

A rewriting web proxy for testing interactions between your browser and external sites. Works with ruby + rspec.
MIT License
656 stars 170 forks source link

eventmachine not initialized - proxy isn't working #253

Open knagode opened 5 years ago

knagode commented 5 years ago

I am getting this error

An error occurred in an `after(:suite)` hook.
Failure/Error: Socket.unpack_sockaddr_in(EM.get_sockname(@signature)).first

RuntimeError:
  eventmachine not initialized: evma_get_sockname
# /Users/klemennagode/.rvm/gems/ruby-2.3.7/gems/puffing-billy-1.1.2/lib/billy/proxy.rb:43:in `get_sockname'

Anyone has idea why?

My setup in rails_helper.rb:

Capybara.register_driver :chrome do |app|
  options = Selenium::WebDriver::Chrome::Options.new
  options.add_argument('--lang=de')
  options.add_argument('--verbose')
  options.add_argument("--proxy-server=#{Billy.proxy.host}:#{Billy.proxy.port}")

  Capybara::Selenium::Driver.new(
    app,
    browser: :chrome,
    options: options
  )
end

Capybara.javascript_driver = :chrome 

When I run test chrome looks like this:

screenshot 2018-10-17 17 20 37

ronwsmith commented 5 years ago

@knagode can you try running on the branch in this PR and see if it works? https://github.com/oesmith/puffing-billy/pull/251

knagode commented 5 years ago

@knagode I tried but it didn't help. Other ideas maybe?

ronwsmith commented 5 years ago

Looks like someone had a similar issue a couple years ago: https://github.com/oesmith/puffing-billy/issues/43#issuecomment-256453041

gagalago commented 5 years ago

this seems to be related to https://github.com/oesmith/puffing-billy/pull/239 but I can't understand how exactly

knagode commented 5 years ago

I tried to install it in clean project on same machine and it worked.. Apparently there is a conflict with another gem/configuration.

I removed all the spec configuration in problematic project (in files rspec_helper.rb and spec_helper.rb).

I noticed that proxy started working but still there is an error

An error occurred in an `after(:suite)` hook.
Failure/Error: Socket.unpack_sockaddr_in(EM.get_sockname(@signature)).first
knagode commented 5 years ago

I found that problem is happening due to WebMock which we heavily use. I think that both gems are super useful and they should work together.

Example controller method:

  def test_page
    data = HTTParty.get('http://yahoo.com/data.json', format: :json)
    # stub code: WebMock.stub_request('http://yahoo.com/data.json').to_return(body: { data: 'fake' }.to_json, headers: {})

    render html: ('<html><body><b>Data=' + data.to_json + '</b> <script src="http://google.com/script.js"></script></body></html>').html_safe
    # stub code:  proxy.stub('http://google.com/script.js').and_return(:text => "document.write('Yeeeyyy')")
  end

Is there no way to make those two gems work together?

ronwsmith commented 5 years ago

In this example, what do you expect WebMock to do and what do you expect PuffingBilly to do?

knagode commented 5 years ago

@ronwsmith Thnx for question. I would like to stub both Rails&browser based requests:

Browser specific stub (via Puffing Billy proxy):

proxy.stub('http://google.com/script.js').and_return(:text => "document.write('Yeeeyyy')")

Ruby/Rails specific stub (via WebMock) :

WebMock.stub_request('http://yahoo.com/data.json').to_return(body: { data: 'fake' }.to_json, headers: {})

I would like to block all network requests inside tests and wherever they occur by default(either on Rails or browser side). I would then whitelist/handle some specific requests via PuffiingBilly/WebMock.

ronwsmith commented 5 years ago

@knagode so it seems to work now but you still get an error in the after suite? Maybe we can just add a check to only shut it down if it's still running?

knagode commented 5 years ago

@ronwsmith I was slowly removing gems from my repo and managed to fix eventmachine not initialized: evma_get_sockname.

In my case problem was: gem fake_stripe. Anyway I wasn't able to use Puffing Billy because it doesnt allow me to use WebMock & Chrome proxy together. Why is this not possible? Do you see that this gem would be really powerful if it would allow co-existance of both as they are both super important gems ... Do you know why exactly do they not work together? What should be changed in order to use both?

ronwsmith commented 5 years ago

Puffing-billy is a proxy itself. If you use it as the proxy in Chrome, it will work just fine. Not sure what other proxy settings you're using in Chrome or why, but as far as I know you can only use one proxy in any browser.

knagode commented 5 years ago

dSure. PuffingBilly is proxy for browser based requests.

But if you are building app which is also making requests to external servers (e.g. requests to Stripe, Facebook Graph, etc ...) you sooner or later need something for stubbing those requests. That is why we use WebMock.

I would expect that those 2 gems would work together because they are solving 2 problems. I saw that I am not the only one who expected that this to work out of the box.

ronwsmith commented 5 years ago

Have you tried the suggestions in that linked issue? Happy to accept a PR with README changes that document it better.

fukayatsu commented 5 years ago

I saw the same error(eventmachine not initialized: evma_get_sockname) when using knapsackpro queue mode. It seems that knapsackpro queue mode calls after(:suite) hook multiple times on a job.

My current workaround is:

# rails_helper.rb

...

module BillyProxyPatch
  # @see https://github.com/oesmith/puffing-billy/blob/v1.1.2/lib/billy/proxy.rb#L26
  def stop
    super
    @signature = nil
  end
end

Billy::Proxy.prepend(BillyProxyPatch)
ronwsmith commented 5 years ago

Just updated eventmachine in 1.1.3. Please try it out and see if this issue persists.

fukayatsu commented 5 years ago

This issue persists on puffing-billy v1.1.3 with knapsack_pro queue mode.

An error occurred in an `after(:suite)` hook.
--
  | Failure/Error: Socket.unpack_sockaddr_in(EM.get_sockname(@signature)).first
  |  
  | RuntimeError:
  | eventmachine not initialized: evma_get_sockname
  | # /bundle/gems/puffing-billy-1.1.3/lib/billy/proxy.rb:43:in `get_sockname'
  | # /bundle/gems/puffing-billy-1.1.3/lib/billy/proxy.rb:43:in `port'
  | # /bundle/gems/puffing-billy-1.1.3/lib/billy/proxy.rb:29:in `stop'
  | # /bundle/gems/puffing-billy-1.1.3/lib/billy/init/rspec.rb:17:in `block (2 levels) in <top (required)>'
  | # /bundle/gems/knapsack_pro-1.2.0/lib/knapsack_pro/runners/queue/rspec_runner.rb:81:in `run_tests'
  | # /bundle/gems/knapsack_pro-1.2.0/lib/knapsack_pro/runners/queue/rspec_runner.rb:34:in `run'
  | # /bundle/gems/knapsack_pro-1.2.0/lib/tasks/queue/rspec.rake:6:in `block (3 levels) in <top (required)>'
ronwsmith commented 5 years ago

@AlanFoster can you take a look at this issue? Seems to be introduced by your PR https://github.com/oesmith/puffing-billy/pull/239 . Thanks!

julioolvr commented 5 years ago

I don't want to add much noise, but we've been looking into an issue similar to this one today. Seems like eventmachine's reactor is a singleton, right? So other gems that use it could theoretically stop it before puffing-billy does? We'll work around this for now by adding a check for EM.reactor_running? before Billy::Proxy#stop and see how that goes, so just sharing in case it makes sense to add this to puffing-billy.

ronwsmith commented 5 years ago

@knagode is this still an issue for you?

@julioolvr how did that workaround work? If it works, can you submit a PR with it? Thanks!

julioolvr commented 5 years ago

We haven’t had issues in a while to the point I had completely forgot about this, so I guess the workaround was a success. I’ll see if I have time to send a PR during the week, but in the meantime this is the whole code for the patch (we have it in our rails_helper.rb file)

# Patch `puffing-billy`'s proxy so that it doesn't try to stop
# eventmachine's reactor if it's not running.
module BillyProxyPatch
  def stop
    return unless EM.reactor_running?

    super
  end
end

Billy::Proxy.prepend(BillyProxyPatch)
julioolvr commented 5 years ago

I looked a bit into opening a PR but I'm not sure how I'd write a test for it. Additionally, I had some issues bundle installing on macOS (when trying to compile capybara-webkit, apparently) and I wasn't able to build an image out of the provided Dockerfile. In any case, the change would literally be adding that guard clause with EM.reactor_running?, in case someone with the project already up and running wants to give it a try.

thbar commented 4 years ago

@julioolvr thanks for your patch, which apparently removes the error in my case too.

ArturT commented 4 years ago

@fukayatsu You asked about the case when puffing-billy gem fails when using knapsack_pro gem in Queue Mode to run your tests in parallel on CI server. I got patch fix from one of users that was helpful:

# rails_helper.rb or spec_helper.rb

# A patch to `puffing-billy`'s proxy so that it doesn't try to stop
# eventmachine's reactor if it's not running.
module BillyProxyPatch
  def stop
    return unless EM.reactor_running?
    super
  end
end
Billy::Proxy.prepend(BillyProxyPatch)

# A patch to `puffing-billy` to start EM if it has been stopped
Billy.module_eval do
  def self.proxy
    if @billy_proxy.nil? || !(EventMachine.reactor_running? && EventMachine.reactor_thread.alive?)
      proxy = Billy::Proxy.new
      proxy.start
      @billy_proxy = proxy
    else
      @billy_proxy
    end
  end
end

if ENV["KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC"]
  KnapsackPro::Hooks::Queue.before_queue do
    # executes before Queue Mode starts work
    Billy.proxy.start
  end

  KnapsackPro::Hooks::Queue.after_queue do
    # executes after Queue Mode finishes work
    Billy.proxy.stop
  end
end

I've updated FAQ in my docs https://github.com/KnapsackPro/knapsack_pro-ruby#how-to-configure-puffing-billy-gem-with-knapsack-pro-queue-mode

ronwsmith commented 4 years ago

Happy to accept a PR with that patch (and tests) if someone wants to put one up.

dlozano commented 3 years ago

I am also having the this issue when I switch to unicorn as Capybara rack server. In addition to @ArturT patch I needed to patch port_in_use?

I use both puffing-billy and webmock

module BillyProxyPatch
  def stop
    return unless EM.reactor_running?
    super
  end

  def port_in_use?(port)
    return unless EM.reactor_running?
    super
  end
end
senid231 commented 2 years ago

I have a similar problem but none of above fixes didn't work for me

following works for me

module BillyProxyPatch
  protected

  def port_in_use?(port)
    Timeout::timeout(1) do
      super
    end
  rescue Timeout::Error
    false
  end
end

Billy::Proxy.prepend(BillyProxyPatch)

because in my case TCPSocket#new hangs for 60 seconds (then timeout in wait_for_server_shutdown being called)

PS TCPSocket#new has a connection_timeout option, but we use socksify as a dependency of one of our gems which monkey patch TCPSocket and removes this option.