Skip to content

FIX: Ensure Net::HTTP socket type is StubSocket.#1067

Open
sealabcore wants to merge 3 commits into
bblimke:masterfrom
sealabcore:master
Open

FIX: Ensure Net::HTTP socket type is StubSocket.#1067
sealabcore wants to merge 3 commits into
bblimke:masterfrom
sealabcore:master

Conversation

@sealabcore

Copy link
Copy Markdown

When running my tests related to opensearch using the searchkick gem I was getting intermittent errors from the Webmock library as seen below. After some debug logging I noticed that StubSocket wasn't always the Net::HTTP.socket_type as expected. This change ensures the socket_type is always StubSocket as opposed to Net::BufferedIO.

ankane/searchkick#1692

ArgumentError: wrong number of arguments (given 0, expected 1)
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/net-protocol-0.2.2/lib/net/protocol.rb:116:in `initialize'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/webmock-3.23.1/lib/webmock/http_lib_adapters/net_http.rb:121:in `new'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/webmock-3.23.1/lib/webmock/http_lib_adapters/net_http.rb:121:in `start_without_connect'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/webmock-3.23.1/lib/webmock/http_lib_adapters/net_http.rb:153:in `start'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/net-http-persistent-4.0.2/lib/net/http/persistent.rb:662:in `start'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/net-http-persistent-4.0.2/lib/net/http/persistent.rb:867:in `reset'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/net-http-persistent-4.0.2/lib/net/http/persistent.rb:604:in `connection_for'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/net-http-persistent-4.0.2/lib/net/http/persistent.rb:892:in `request'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/faraday-net_http_persistent-2.0.2/lib/faraday/adapter/net_http_persistent.rb:68:in `perform_request'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/faraday-net_http-2.1.0/lib/faraday/adapter/net_http.rb:66:in `block in call'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/faraday-2.0.1/lib/faraday/adapter.rb:45:in `connection'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/faraday-net_http-2.1.0/lib/faraday/adapter/net_http.rb:65:in `call'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/faraday_middleware-aws-sigv4-1.0.1/lib/faraday_middleware/request/aws_sigv4.rb:18:in `call'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/searchkick-5.3.1/lib/searchkick/middleware.rb:16:in `call'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/faraday-2.0.1/lib/faraday/rack_builder.rb:153:in `build_response'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/faraday-2.0.1/lib/faraday/connection.rb:445:in `run_request'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/opensearch-ruby-3.4.0/lib/opensearch/transport/transport/http/faraday.rb:56:in `block in perform_request'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/opensearch-ruby-3.4.0/lib/opensearch/transport/transport/base.rb:297:in `perform_request'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/opensearch-ruby-3.4.0/lib/opensearch/transport/transport/http/faraday.rb:45:in `perform_request'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/opensearch-ruby-3.4.0/lib/opensearch/transport/client.rb:191:in `perform_request'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/opensearch-ruby-3.4.0/lib/opensearch.rb:48:in `method_missing'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/opensearch-ruby-3.4.0/lib/opensearch/api/namespace/common.rb:46:in `perform_request'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/opensearch-ruby-3.4.0/lib/opensearch/api/actions/indices/get_alias.rb:64:in `get_alias'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/searchkick-5.3.1/lib/searchkick/index.rb:111:in `all_indices'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/searchkick-5.3.1/lib/searchkick/index.rb:125:in `clean_indices'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/searchkick-5.3.1/lib/searchkick/index.rb:361:in `full_reindex'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/searchkick-5.3.1/lib/searchkick/index.rb:254:in `reindex'
    /Users/miketaylor/.rbenv/versions/3.2.4/lib/ruby/gems/3.2.0/gems/searchkick-5.3.1/lib/searchkick/model.rb:77:in `searchkick_reindex'
    test/integration/graphql/searches_test.rb:18:in `execute'
    test/integration/graphql/searches_test.rb:32:in `block in <class:SearchesTest>'

@sealabcore

Copy link
Copy Markdown
Author

Getting this error when trying to run tests locally

 /Users/miketaylor/dev/webmock [master]% bundle exec rake test
/Users/miketaylor/.rbenv/versions/3.1.3/lib/ruby/gems/3.1.0/gems/async-http-0.74.0/lib/async/http/endpoint.rb:25:in `<class:Endpoint>': uninitialized constant URI::WSS (NameError)

				'wss' => URI::WSS,
				            ^^^^^
	from /Users/miketaylor/.rbenv/versions/3.1.3/lib/ruby/gems/3.1.0/gems/async-http-0.74.0/lib/async/http/endpoint.rb:20:in `<module:HTTP>'
	from /Users/miketaylor/.rbenv/versions/3.1.3/lib/ruby/gems/3.1.0/gems/async-http-0.74.0/lib/async/http/endpoint.rb:18:in `<module:Async>'
	from /Users/miketaylor/.rbenv/versions/3.1.3/lib/ruby/gems/3.1.0/gems/async-http-0.74.0/lib/async/http/endpoint.rb:17:in `<top (required)>'
	from /Users/miketaylor/.rbenv/versions/3.1.3/lib/ruby/gems/3.1.0/gems/async-http-0.74.0/lib/async/http/internet.rb:8:in `require_relative'
	from /Users/miketaylor/.rbenv/versions/3.1.3/lib/ruby/gems/3.1.0/gems/async-http-0.74.0/lib/async/http/internet.rb:8:in `<top (required)>'
	from /Users/miketaylor/.rbenv/versions/3.1.3/lib/ruby/gems/3.1.0/gems/async-http-0.74.0/lib/async/http.rb:11:in `require_relative'
	from /Users/miketaylor/.rbenv/versions/3.1.3/lib/ruby/gems/3.1.0/gems/async-http-0.74.0/lib/async/http.rb:11:in `<top (required)>'
	from /Users/miketaylor/dev/webmock/lib/webmock/http_lib_adapters/async_http_client_adapter.rb:5:in `require'
	from /Users/miketaylor/dev/webmock/lib/webmock/http_lib_adapters/async_http_client_adapter.rb:5:in `<top (required)>'
	from /Users/miketaylor/dev/webmock/lib/webmock.rb:59:in `require_relative'
	from /Users/miketaylor/dev/webmock/lib/webmock.rb:59:in `<top (required)>'
	from /Users/miketaylor/dev/webmock/lib/webmock/test_unit.rb:4:in `require'
	from /Users/miketaylor/dev/webmock/lib/webmock/test_unit.rb:4:in `<top (required)>'
	from /Users/miketaylor/dev/webmock/test/test_helper.rb:6:in `require'
	from /Users/miketaylor/dev/webmock/test/test_helper.rb:6:in `<top (required)>'
	from /Users/miketaylor/dev/webmock/test/test_webmock.rb:1:in `require'
	from /Users/miketaylor/dev/webmock/test/test_webmock.rb:1:in `<top (required)>'
	from /Users/miketaylor/.rbenv/versions/3.1.3/lib/ruby/gems/3.1.0/gems/rake-13.2.1/lib/rake/rake_test_loader.rb:21:in `require'
	from /Users/miketaylor/.rbenv/versions/3.1.3/lib/ruby/gems/3.1.0/gems/rake-13.2.1/lib/rake/rake_test_loader.rb:21:in `block in <main>'
	from /Users/miketaylor/.rbenv/versions/3.1.3/lib/ruby/gems/3.1.0/gems/rake-13.2.1/lib/rake/rake_test_loader.rb:6:in `select'
	from /Users/miketaylor/.rbenv/versions/3.1.3/lib/ruby/gems/3.1.0/gems/rake-13.2.1/lib/rake/rake_test_loader.rb:6:in `<main>'
rake aborted!
Command failed with status (1)
/Users/miketaylor/.rbenv/versions/3.1.3/bin/bundle:25:in `load'
/Users/miketaylor/.rbenv/versions/3.1.3/bin/bundle:25:in `<main>'
Tasks: TOP => test
(See full trace by running task with --trace)

@bblimke

bblimke commented Sep 18, 2024

Copy link
Copy Markdown
Owner

@sealabcore Thank you for your work on this PR. I've noticed that while the tests in master are now passing, there aren't any new tests associated with this specific change. Could you please provide some context on why this particular modification is necessary?

I'm especially interested in understanding the rationale behind assigning @socket to be StubSocket only when it's an instance of Net::BufferedIO.

Given the lack of new tests, could you explain how we can be confident that this change works as intended and doesn't introduce any regressions? Perhaps you could suggest some test cases that would effectively validate this new behavior?

@rodovich

Copy link
Copy Markdown

Thought I'd bump this because we ran into this error with our app recently as well. (Same exception from the same line in webmock, though the rest of the stack was a bit different because we're using it with capybara + selenium.) For us, the error was happening when enabling WebMock, then disabling it, but continuing to use a cached instance of the mocked version of Net::HTTP. (Specifically, capybara/selenium were caching a mocked Net::HTTP instance that they used to communicate with the browser.)

After WebMock has been disabled, (the real implementation of) Net::HTTP.socket_type returns Net::BufferedIO, and Net::BufferedIO#initialize's signature is incompatible with StubSocket's, hence the error when calling Net::HTTP.socket_type.new without any parameters.

I'm not super familiar with WebMock's internals, but if I'm understanding well enough I think it would be appropriate (and a little simpler than the change in this PR) for @webMockNetHTTP to call self.class.socket_type.new rather than Net::HTTP.socket_type.new. Then a mocked Net::HTTP instance would always get a StubSocket—which is what it seems to expect—even if the Net::HTTP class is no longer mocked.

We ended up finding a different way to mock remote APIs in tests and removing WebMock from those tests, but I went back and tested a version using self.class.socket_type.new and it did fix the errors in our app. The change as implemented in the PR did as well.

Hope this is helpful for you @bblimke.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants