webmock-3.18.1/ 0000755 0000041 0000041 00000000000 14333126774 013275 5 ustar www-data www-data webmock-3.18.1/test/ 0000755 0000041 0000041 00000000000 14333126774 014254 5 ustar www-data www-data webmock-3.18.1/test/http_request.rb 0000644 0000041 0000041 00000001312 14333126774 017325 0 ustar www-data www-data require 'ostruct'
module HttpRequestTestHelper
def http_request(method, uri, options = {})
begin
uri = URI.parse(uri)
rescue
uri = Addressable::URI.heuristic_parse(uri)
end
response = nil
clazz = ::Net::HTTP.const_get("#{method.to_s.capitalize}")
req = clazz.new("#{uri.path}#{uri.query ? '?' : ''}#{uri.query}", options[:headers])
req.basic_auth uri.user, uri.password if uri.user
http = ::Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true if uri.scheme == "https"
response = http.start {|http|
http.request(req, options[:body])
}
OpenStruct.new({
body: response.body,
headers: response,
status: response.code })
end
end webmock-3.18.1/test/test_webmock.rb 0000644 0000041 0000041 00000000633 14333126774 017271 0 ustar www-data www-data require File.expand_path(File.dirname(__FILE__) + '/test_helper')
require File.expand_path(File.dirname(__FILE__) + '/shared_test')
class TestWebMock < Test::Unit::TestCase
include SharedTest
def teardown
# Ensure global Test::Unit teardown was called
assert_empty WebMock::RequestRegistry.instance.requested_signatures.hash
assert_empty WebMock::StubRegistry.instance.request_stubs
end
end
webmock-3.18.1/test/shared_test.rb 0000644 0000041 0000041 00000011603 14333126774 017107 0 ustar www-data www-data require File.expand_path(File.dirname(__FILE__) + '/http_request')
module SharedTest
include HttpRequestTestHelper
def setup
super
@stub_http = stub_http_request(:any, "http://www.example.com")
@stub_https = stub_http_request(:any, "https://www.example.com")
end
def test_assert_requested_with_stub_and_block_raises_error
assert_raises ArgumentError do
assert_requested(@stub_http) {}
end
end
def test_assert_not_requested_with_stub_and_block_raises_error
assert_raises ArgumentError do
assert_not_requested(@stub_http) {}
end
end
def test_error_on_non_stubbed_request
assert_raise_with_message(WebMock::NetConnectNotAllowedError, %r{Real HTTP connections are disabled. Unregistered request: GET http://www.example.net/ with headers}) do
http_request(:get, "http://www.example.net/")
end
end
def test_verification_that_expected_request_occured
http_request(:get, "http://www.example.com/")
assert_requested(:get, "http://www.example.com", times: 1)
assert_requested(:get, "http://www.example.com")
end
def test_verification_that_expected_stub_occured
http_request(:get, "http://www.example.com/")
assert_requested(@stub_http, times: 1)
assert_requested(@stub_http)
end
def test_verification_that_expected_request_didnt_occur
expected_message = "The request GET http://www.example.com/ was expected to execute 1 time but it executed 0 times"
expected_message += "\n\nThe following requests were made:\n\nNo requests were made.\n============================================================"
assert_fail(expected_message) do
assert_requested(:get, "http://www.example.com")
end
end
def test_verification_that_expected_stub_didnt_occur
expected_message = "The request ANY http://www.example.com/ was expected to execute 1 time but it executed 0 times"
expected_message += "\n\nThe following requests were made:\n\nNo requests were made.\n============================================================"
assert_fail(expected_message) do
assert_requested(@stub_http)
end
end
def test_verification_that_expected_request_occured_with_body_and_headers
http_request(:get, "http://www.example.com/",
body: "abc", headers: {'A' => 'a'})
assert_requested(:get, "http://www.example.com",
body: "abc", headers: {'A' => 'a'})
end
def test_verification_that_expected_request_occured_with_query_params
stub_request(:any, "http://www.example.com").with(query: hash_including({"a" => ["b", "c"]}))
http_request(:get, "http://www.example.com/?a[]=b&a[]=c&x=1")
assert_requested(:get, "http://www.example.com",
query: hash_including({"a" => ["b", "c"]}))
end
def test_verification_that_expected_request_not_occured_with_query_params
stub_request(:any, 'http://www.example.com').with(query: hash_including(a: ['b', 'c']))
stub_request(:any, 'http://www.example.com').with(query: hash_excluding(a: ['b', 'c']))
http_request(:get, 'http://www.example.com/?a[]=b&a[]=c&x=1')
assert_not_requested(:get, 'http://www.example.com', query: hash_excluding('a' => ['b', 'c']))
end
def test_verification_that_expected_request_occured_with_excluding_query_params
stub_request(:any, 'http://www.example.com').with(query: hash_excluding('a' => ['b', 'c']))
http_request(:get, 'http://www.example.com/?a[]=x&a[]=y&x=1')
assert_requested(:get, 'http://www.example.com', query: hash_excluding('a' => ['b', 'c']))
end
def test_verification_that_non_expected_request_didnt_occur
expected_message = %r(The request GET http://www.example.com/ was not expected to execute but it executed 1 time\n\nThe following requests were made:\n\nGET http://www.example.com/ with headers .+ was made 1 time\n\n============================================================)
assert_fail(expected_message) do
http_request(:get, "http://www.example.com/")
assert_not_requested(:get, "http://www.example.com")
end
end
def test_refute_requested_alias
expected_message = %r(The request GET http://www.example.com/ was not expected to execute but it executed 1 time\n\nThe following requests were made:\n\nGET http://www.example.com/ with headers .+ was made 1 time\n\n============================================================)
assert_fail(expected_message) do
http_request(:get, "http://www.example.com/")
refute_requested(:get, "http://www.example.com")
end
end
def test_verification_that_non_expected_stub_didnt_occur
expected_message = %r(The request ANY http://www.example.com/ was not expected to execute but it executed 1 time\n\nThe following requests were made:\n\nGET http://www.example.com/ with headers .+ was made 1 time\n\n============================================================)
assert_fail(expected_message) do
http_request(:get, "http://www.example.com/")
assert_not_requested(@stub_http)
end
end
end
webmock-3.18.1/test/test_helper.rb 0000644 0000041 0000041 00000001157 14333126774 017123 0 ustar www-data www-data require 'rubygems'
$LOAD_PATH.unshift(File.dirname(__FILE__))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
require 'webmock/test_unit'
require 'test/unit'
class Test::Unit::TestCase
AssertionFailedError = Test::Unit::AssertionFailedError rescue MiniTest::Assertion
def assert_raise_with_message(e, message, &block)
e = assert_raises(e, &block)
if message.is_a?(Regexp)
assert_match(message, e.message)
else
assert_equal(message, e.message)
end
end
def assert_fail(message, &block)
assert_raise_with_message(AssertionFailedError, message, &block)
end
end
webmock-3.18.1/webmock.gemspec 0000644 0000041 0000041 00000004626 14333126774 016301 0 ustar www-data www-data # -*- encoding: utf-8 -*-
$:.push File.expand_path('../lib', __FILE__)
require 'webmock/version'
Gem::Specification.new do |s|
s.name = 'webmock'
s.version = WebMock::VERSION
s.platform = Gem::Platform::RUBY
s.authors = ['Bartosz Blimke']
s.email = ['bartosz.blimke@gmail.com']
s.homepage = 'https://github.com/bblimke/webmock'
s.summary = %q{Library for stubbing HTTP requests in Ruby.}
s.description = %q{WebMock allows stubbing HTTP requests and setting expectations on HTTP requests.}
s.license = "MIT"
s.metadata = {
'bug_tracker_uri' => 'https://github.com/bblimke/webmock/issues',
'changelog_uri' => "https://github.com/bblimke/webmock/blob/v#{s.version}/CHANGELOG.md",
'documentation_uri' => "https://www.rubydoc.info/gems/webmock/#{s.version}",
'source_code_uri' => "https://github.com/bblimke/webmock/tree/v#{s.version}",
'wiki_uri' => 'https://github.com/bblimke/webmock/wiki'
}
s.required_ruby_version = '>= 2.3'
s.add_dependency 'addressable', '>= 2.8.0'
s.add_dependency 'crack', '>= 0.3.2'
s.add_dependency 'hashdiff', ['>= 0.4.0', '< 2.0.0']
unless RUBY_PLATFORM =~ /java/
s.add_development_dependency 'patron', '>= 0.4.18'
s.add_development_dependency 'curb', '>= 0.7.16'
s.add_development_dependency 'typhoeus', '>= 0.5.0'
s.add_development_dependency 'em-http-request', '>= 1.0.2'
s.add_development_dependency 'em-synchrony', '>= 1.0.0'
end
s.add_development_dependency 'http', '>= 0.8.0'
s.add_development_dependency 'manticore', '>= 0.5.1' if RUBY_PLATFORM =~ /java/
s.add_development_dependency 'rack', ((RUBY_VERSION < '2.2.2') ? '1.6.0' : '> 1.6')
s.add_development_dependency 'rspec', '>= 3.1.0'
s.add_development_dependency 'httpclient', '>= 2.2.4'
s.add_development_dependency 'excon', '>= 0.27.5'
s.add_development_dependency 'async-http', '>= 0.48.0'
s.add_development_dependency 'minitest', '>= 5.0.0'
s.add_development_dependency 'test-unit', '>= 3.0.0'
s.add_development_dependency 'rdoc', '> 3.5.0'
s.add_development_dependency 'webrick'
s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ['lib']
end
webmock-3.18.1/README.md 0000644 0000041 0000041 00000076045 14333126774 014570 0 ustar www-data www-data WebMock
=======
[](http://badge.fury.io/rb/webmock)
[](https://github.com/bblimke/webmock/actions)
[](https://codeclimate.com/github/bblimke/webmock)
[](https://github.com/markets/awesome-ruby)
[](http://inch-ci.org/github/bblimke/webmock)
[](https://dependabot.com/compatibility-score.html?dependency-name=webmock&package-manager=bundler&version-scheme=semver)
Library for stubbing and setting expectations on HTTP requests in Ruby.
Features
--------
* Stubbing HTTP requests at low http client lib level (no need to change tests when you change HTTP library)
* Setting and verifying expectations on HTTP requests
* Matching requests based on method, URI, headers and body
* Smart matching of the same URIs in different representations (also encoded and non encoded forms)
* Smart matching of the same headers in different representations.
* Support for Test::Unit
* Support for RSpec
* Support for MiniTest
Supported HTTP libraries
------------------------
* [Async::HTTP::Client](https://github.com/socketry/async-http)
* [Curb](https://github.com/taf2/curb) (currently only Curb::Easy)
* [EM-HTTP-Request](https://github.com/igrigorik/em-http-request)
* [Excon](https://github.com/excon/excon)
* [HTTPClient](https://github.com/nahi/httpclient)
* [HTTP Gem (also known as http.rb)](https://github.com/httprb/http)
* [httpx](https://honeyryderchuck.gitlab.io/httpx/wiki/Webmock-Adapter)
* [Manticore](https://github.com/cheald/manticore)
* [Net::HTTP](https://ruby-doc.org/stdlib-2.7.0/libdoc/net/http/rdoc/Net/HTTP.html) and other libraries based on Net::HTTP, e.g.:
* [HTTParty](https://github.com/jnunemaker/httparty)
* [REST Client](https://github.com/rest-client/rest-client)
* [Patron](https://github.com/toland/patron)
* [Typhoeus](https://github.com/typhoeus/typhoeus) (currently only Typhoeus::Hydra)
Supported Ruby Interpreters
---------------------------
* MRI 2.5
* MRI 2.6
* MRI 2.7
* JRuby
* Rubinius
## Installation
```bash
gem install webmock
```
or alternatively:
```ruby
# add to your Gemfile
group :test do
gem "webmock"
end
```
### or to install the latest development version from github master
git clone http://github.com/bblimke/webmock.git
cd webmock
rake install
## Upgrading from v1.x to v2.x
WebMock 2.x has changed somewhat since version 1.x. Changes are listed in [CHANGELOG.md](CHANGELOG.md)
### Cucumber
Create a file `features/support/webmock.rb` with the following contents:
```ruby
require 'webmock/cucumber'
```
### MiniTest
Add the following code to `test/test_helper`:
```ruby
require 'webmock/minitest'
```
### RSpec
Add the following code to `spec/spec_helper`:
```ruby
require 'webmock/rspec'
```
### Test::Unit
Add the following code to `test/test_helper.rb`
```ruby
require 'webmock/test_unit'
```
### Outside a test framework
You can also use WebMock outside a test framework:
```ruby
require 'webmock'
include WebMock::API
WebMock.enable!
```
# Examples
## Stubbing
### Stubbed request based on uri only and with the default response
```ruby
stub_request(:any, "www.example.com")
Net::HTTP.get("www.example.com", "/") # ===> Success
```
### Stubbing requests based on method, uri, body and headers
```ruby
stub_request(:post, "www.example.com").
with(body: "abc", headers: { 'Content-Length' => 3 })
uri = URI.parse("http://www.example.com/")
req = Net::HTTP::Post.new(uri.path)
req['Content-Length'] = 3
res = Net::HTTP.start(uri.host, uri.port) do |http|
http.request(req, "abc")
end # ===> Success
```
### Matching request body and headers against regular expressions
```ruby
stub_request(:post, "www.example.com").
with(body: /world$/, headers: {"Content-Type" => /image\/.+/}).
to_return(body: "abc")
uri = URI.parse('http://www.example.com/')
req = Net::HTTP::Post.new(uri.path)
req['Content-Type'] = 'image/png'
res = Net::HTTP.start(uri.host, uri.port) do |http|
http.request(req, 'hello world')
end # ===> Success
```
### Matching request body against a hash. Body can be URL-Encoded, JSON or XML.
```ruby
stub_request(:post, "www.example.com").
with(body: {data: {a: '1', b: 'five'}})
RestClient.post('www.example.com', "data[a]=1&data[b]=five",
content_type: 'application/x-www-form-urlencoded') # ===> Success
RestClient.post('www.example.com', '{"data":{"a":"1","b":"five"}}',
content_type: 'application/json') # ===> Success
RestClient.post('www.example.com', '',
content_type: 'application/xml') # ===> Success
```
### Matching request body against partial hash.
```ruby
stub_request(:post, "www.example.com").
with(body: hash_including({data: {a: '1', b: 'five'}}))
RestClient.post('www.example.com', "data[a]=1&data[b]=five&x=1",
:content_type => 'application/x-www-form-urlencoded') # ===> Success
```
### Matching custom request headers
```ruby
stub_request(:any, "www.example.com").
with(headers:{ 'Header-Name' => 'Header-Value' })
uri = URI.parse('http://www.example.com/')
req = Net::HTTP::Post.new(uri.path)
req['Header-Name'] = 'Header-Value'
res = Net::HTTP.start(uri.host, uri.port) do |http|
http.request(req, 'abc')
end # ===> Success
```
### Matching multiple headers with the same name
```ruby
stub_request(:get, 'www.example.com').
with(headers: {'Accept' => ['image/jpeg', 'image/png'] })
req = Net::HTTP::Get.new("/")
req['Accept'] = ['image/png']
req.add_field('Accept', 'image/jpeg')
Net::HTTP.start("www.example.com") {|http| http.request(req) } # ===> Success
```
### Matching requests against provided block
```ruby
stub_request(:post, "www.example.com").with { |request| request.body == "abc" }
RestClient.post('www.example.com', 'abc') # ===> Success
```
### Request with basic authentication header
```ruby
stub_request(:get, "www.example.com").with(basic_auth: ['user', 'pass'])
# or
# stub_request(:get, "www.example.com").
# with(headers: {'Authorization' => "Basic #{ Base64.strict_encode64('user:pass').chomp}"})
Net::HTTP.start('www.example.com') do |http|
req = Net::HTTP::Get.new('/')
req.basic_auth 'user', 'pass'
http.request(req)
end # ===> Success
```
##### Important! Since version 2.0.0, WebMock does not match credentials provided in Authorization header and credentials provided in the userinfo of a url. I.e. `stub_request(:get, "user:pass@www.example.com")` does not match a request with credentials provided in the Authorization header.
### Request with basic authentication in the url
```ruby
stub_request(:get, "user:pass@www.example.com")
RestClient.get('user:pass@www.example.com') # ===> Success
```
### Matching uris using regular expressions
```ruby
stub_request(:any, /example/)
Net::HTTP.get('www.example.com', '/') # ===> Success
```
### Matching uris using lambda
```ruby
stub_request(:any, ->(uri) { true })
```
### Matching uris using RFC 6570 - Basic Example
```ruby
uri_template = Addressable::Template.new "www.example.com/{id}/"
stub_request(:any, uri_template)
Net::HTTP.get('www.example.com', '/webmock/') # ===> Success
```
### Matching uris using RFC 6570 - Advanced Example
```ruby
uri_template =
Addressable::Template.new "www.example.com/thing/{id}.json{?x,y,z}{&other*}"
stub_request(:any, uri_template)
Net::HTTP.get('www.example.com',
'/thing/5.json?x=1&y=2&z=3&anyParam=4') # ===> Success
```
### Matching query params using hash
```ruby
stub_request(:get, "www.example.com").with(query: {"a" => ["b", "c"]})
RestClient.get("http://www.example.com/?a[]=b&a[]=c") # ===> Success
```
### Matching partial query params using hash
```ruby
stub_request(:get, "www.example.com").
with(query: hash_including({"a" => ["b", "c"]}))
RestClient.get("http://www.example.com/?a[]=b&a[]=c&x=1") # ===> Success
```
### Matching partial query params using hash_excluding
```ruby
stub_request(:get, "www.example.com").
with(query: hash_excluding({"a" => "b"}))
RestClient.get("http://www.example.com/?a=b") # ===> Failure
RestClient.get("http://www.example.com/?a=c") # ===> Success
```
### Stubbing with custom response
```ruby
stub_request(:any, "www.example.com").
to_return(body: "abc", status: 200,
headers: { 'Content-Length' => 3 })
Net::HTTP.get("www.example.com", '/') # ===> "abc"
```
Set appropriate Content-Type for HTTParty's `parsed_response`.
```ruby
stub_request(:any, "www.example.com").to_return body: '{}', headers: {content_type: 'application/json'}
```
### Response with body specified as IO object
```ruby
File.open('/tmp/response_body.txt', 'w') { |f| f.puts 'abc' }
stub_request(:any, "www.example.com").
to_return(body: File.new('/tmp/response_body.txt'), status: 200)
Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
```
### Response with custom status message
```ruby
stub_request(:any, "www.example.com").
to_return(status: [500, "Internal Server Error"])
req = Net::HTTP::Get.new("/")
Net::HTTP.start("www.example.com") { |http| http.request(req) }.
message # ===> "Internal Server Error"
```
### Replaying raw responses recorded with `curl -is`
```
curl -is www.example.com > /tmp/example_curl_-is_output.txt
```
```ruby
raw_response_file = File.new("/tmp/example_curl_-is_output.txt")
```
from file
```ruby
stub_request(:get, "www.example.com").to_return(raw_response_file)
```
or string
```ruby
stub_request(:get, "www.example.com").to_return(raw_response_file.read)
```
### Responses dynamically evaluated from block
```ruby
stub_request(:any, 'www.example.net').
to_return { |request| {body: request.body} }
RestClient.post('www.example.net', 'abc') # ===> "abc\n"
```
### Responses dynamically evaluated from lambda
```ruby
stub_request(:any, 'www.example.net').
to_return(lambda { |request| {body: request.body} })
RestClient.post('www.example.net', 'abc') # ===> "abc\n"
```
### Dynamically evaluated raw responses recorded with `curl -is`
`curl -is www.example.com > /tmp/www.example.com.txt`
```ruby
stub_request(:get, "www.example.com").
to_return(lambda { |request| File.new("/tmp/#{request.uri.host.to_s}.txt") })
```
### Responses with dynamically evaluated parts
```ruby
stub_request(:any, 'www.example.net').
to_return(body: lambda { |request| request.body })
RestClient.post('www.example.net', 'abc') # ===> "abc\n"
```
### Rack responses
```ruby
class MyRackApp
def self.call(env)
[200, {}, ["Hello"]]
end
end
stub_request(:get, "www.example.com").to_rack(MyRackApp)
RestClient.post('www.example.com') # ===> "Hello"
```
### Raising errors
#### Exception declared by class
```ruby
stub_request(:any, 'www.example.net').to_raise(StandardError)
RestClient.post('www.example.net', 'abc') # ===> StandardError
```
#### or by exception instance
```ruby
stub_request(:any, 'www.example.net').to_raise(StandardError.new("some error"))
```
#### or by string
```ruby
stub_request(:any, 'www.example.net').to_raise("some error")
```
### Raising timeout errors
```ruby
stub_request(:any, 'www.example.net').to_timeout
RestClient.post('www.example.net', 'abc') # ===> RestClient::RequestTimeout
```
### Multiple responses for repeated requests
```ruby
stub_request(:get, "www.example.com").
to_return({body: "abc"}, {body: "def"})
Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
Net::HTTP.get('www.example.com', '/') # ===> "def\n"
#after all responses are used the last response will be returned infinitely
Net::HTTP.get('www.example.com', '/') # ===> "def\n"
```
### Multiple responses using chained `to_return()`, `to_raise()` or `to_timeout` declarations
```ruby
stub_request(:get, "www.example.com").
to_return({body: "abc"}).then. #then() is just a syntactic sugar
to_return({body: "def"}).then.
to_raise(MyException)
Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
Net::HTTP.get('www.example.com', '/') # ===> "def\n"
Net::HTTP.get('www.example.com', '/') # ===> MyException raised
```
### Specifying number of times given response should be returned
```ruby
stub_request(:get, "www.example.com").
to_return({body: "abc"}).times(2).then.
to_return({body: "def"})
Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
Net::HTTP.get('www.example.com', '/') # ===> "def\n"
```
### Removing unused stubs
```ruby
stub_get = stub_request(:get, "www.example.com")
remove_request_stub(stub_get)
```
### Real requests to network can be allowed or disabled
```ruby
WebMock.allow_net_connect!
stub_request(:any, "www.example.com").to_return(body: "abc")
Net::HTTP.get('www.example.com', '/') # ===> "abc"
Net::HTTP.get('www.something.com', '/') # ===> /.+Something.+/
WebMock.disable_net_connect!
Net::HTTP.get('www.something.com', '/') # ===> Failure
```
### External requests can be disabled while allowing localhost
```ruby
WebMock.disable_net_connect!(allow_localhost: true)
Net::HTTP.get('www.something.com', '/') # ===> Failure
Net::HTTP.get('localhost:9887', '/') # ===> Allowed. Perhaps to Selenium?
```
### External requests can be disabled while allowing specific requests
Allowed requests can be specified in a number of ways.
With a `String` specifying a host name:
```ruby
WebMock.disable_net_connect!(allow: 'www.example.org')
RestClient.get('www.something.com', '/') # ===> Failure
RestClient.get('www.example.org', '/') # ===> Allowed
RestClient.get('www.example.org:8080', '/') # ===> Allowed
```
With a `String` specifying a host name and a port:
```ruby
WebMock.disable_net_connect!(allow: 'www.example.org:8080')
RestClient.get('www.something.com', '/') # ===> Failure
RestClient.get('www.example.org', '/') # ===> Failure
RestClient.get('www.example.org:8080', '/') # ===> Allowed
```
With a `Regexp` matching the URI:
```ruby
WebMock.disable_net_connect!(allow: %r{ample.org/foo})
RestClient.get('www.example.org', '/foo/bar') # ===> Allowed
RestClient.get('sample.org', '/foo') # ===> Allowed
RestClient.get('sample.org', '/bar') # ===> Failure
```
With an object that responds to `#call`, receiving a `URI` object and returning a boolean:
```ruby
denylist = ['google.com', 'facebook.com', 'apple.com']
allowed_sites = lambda{|uri|
denylist.none?{|site| uri.host.include?(site) }
}
WebMock.disable_net_connect!(allow: allowed_sites)
RestClient.get('www.example.org', '/') # ===> Allowed
RestClient.get('www.facebook.com', '/') # ===> Failure
RestClient.get('apple.com', '/') # ===> Failure
```
With an `Array` of any of the above:
```ruby
WebMock.disable_net_connect!(allow: [
lambda{|uri| uri.host.length % 2 == 0 },
/ample.org/,
'bbc.co.uk',
])
RestClient.get('www.example.org', '/') # ===> Allowed
RestClient.get('bbc.co.uk', '/') # ===> Allowed
RestClient.get('bbc.com', '/') # ===> Allowed
RestClient.get('www.bbc.com', '/') # ===> Failure
```
## Connecting on Net::HTTP.start
HTTP protocol has 3 steps: connect, request and response (or 4 with close). Most Ruby HTTP client libraries
treat connect as a part of request step, with the exception of `Net::HTTP` which
allows opening connection to the server separately to the request, by using `Net::HTTP.start`.
WebMock API was also designed with connect being part of request step, and it only allows stubbing
requests, not connections. When `Net::HTTP.start` is called, WebMock doesn't know yet whether
a request is stubbed or not. WebMock by default delays a connection until the request is invoked,
so when there is no request, `Net::HTTP.start` doesn't do anything.
**This means that WebMock breaks the Net::HTTP behaviour by default!**
To workaround this issue, WebMock offers `:net_http_connect_on_start` option,
which can be passed to `WebMock.allow_net_connect!` and `WebMock.disable_net_connect!` methods, i.e.
```ruby
WebMock.allow_net_connect!(net_http_connect_on_start: true)
```
This forces WebMock Net::HTTP adapter to always connect on `Net::HTTP.start`.
## Setting Expectations
### Setting expectations in Test::Unit
```ruby
require 'webmock/test_unit'
stub_request(:any, "www.example.com")
uri = URI.parse('http://www.example.com/')
req = Net::HTTP::Post.new(uri.path)
req['Content-Length'] = 3
res = Net::HTTP.start(uri.host, uri.port) do |http|
http.request(req, 'abc')
end
assert_requested :post, "http://www.example.com",
headers: {'Content-Length' => 3}, body: "abc",
times: 1 # ===> Success
assert_not_requested :get, "http://www.something.com" # ===> Success
assert_requested(:post, "http://www.example.com",
times: 1) { |req| req.body == "abc" }
```
### Expecting real (not stubbed) requests
```ruby
WebMock.allow_net_connect!
Net::HTTP.get('www.example.com', '/') # ===> Success
assert_requested :get, "http://www.example.com" # ===> Success
```
### Setting expectations in Test::Unit on the stub
```ruby
stub_get = stub_request(:get, "www.example.com")
stub_post = stub_request(:post, "www.example.com")
Net::HTTP.get('www.example.com', '/')
assert_requested(stub_get)
assert_not_requested(stub_post)
```
### Setting expectations in RSpec on `WebMock` module
This style is borrowed from [fakeweb-matcher](http://github.com/pat/fakeweb-matcher)
```ruby
require 'webmock/rspec'
expect(WebMock).to have_requested(:get, "www.example.com").
with(body: "abc", headers: {'Content-Length' => 3}).twice
expect(WebMock).not_to have_requested(:get, "www.something.com")
expect(WebMock).to have_requested(:post, "www.example.com").
with { |req| req.body == "abc" }
# Note that the block with `do ... end` instead of curly brackets won't work!
# Why? See this comment https://github.com/bblimke/webmock/issues/174#issuecomment-34908908
expect(WebMock).to have_requested(:get, "www.example.com").
with(query: {"a" => ["b", "c"]})
expect(WebMock).to have_requested(:get, "www.example.com").
with(query: hash_including({"a" => ["b", "c"]}))
expect(WebMock).to have_requested(:get, "www.example.com").
with(body: {"a" => ["b", "c"]},
headers: {'Content-Type' => 'application/json'})
```
### Setting expectations in RSpec with `a_request`
```ruby
expect(a_request(:post, "www.example.com").
with(body: "abc", headers: {'Content-Length' => 3})).
to have_been_made.once
expect(a_request(:post, "www.something.com")).to have_been_made.times(3)
expect(a_request(:post, "www.something.com")).to have_been_made.at_least_once
expect(a_request(:post, "www.something.com")).
to have_been_made.at_least_times(3)
expect(a_request(:post, "www.something.com")).to have_been_made.at_most_twice
expect(a_request(:post, "www.something.com")).to have_been_made.at_most_times(3)
expect(a_request(:any, "www.example.com")).not_to have_been_made
expect(a_request(:post, "www.example.com").with { |req| req.body == "abc" }).
to have_been_made
expect(a_request(:get, "www.example.com").with(query: {"a" => ["b", "c"]})).
to have_been_made
expect(a_request(:get, "www.example.com").
with(query: hash_including({"a" => ["b", "c"]}))).to have_been_made
expect(a_request(:post, "www.example.com").
with(body: {"a" => ["b", "c"]},
headers: {'Content-Type' => 'application/json'})).to have_been_made
```
### Setting expectations in RSpec on the stub
```ruby
stub = stub_request(:get, "www.example.com")
# ... make requests ...
expect(stub).to have_been_requested
```
## Clearing stubs and request history
If you want to reset all current stubs and history of requests use `WebMock.reset!`
```ruby
stub_request(:any, "www.example.com")
Net::HTTP.get('www.example.com', '/') # ===> Success
WebMock.reset!
Net::HTTP.get('www.example.com', '/') # ===> Failure
assert_not_requested :get, "www.example.com" # ===> Success
```
## Clearing request counters
If you want to reset **only** the counters of the executed requests use `WebMock.reset_executed_requests!`
```ruby
stub = stub_request(:get, "www.example.com")
stub2 = stub_request(:get, "www.example2.com")
Net::HTTP.get('www.example.com', '/')
Net::HTTP.get('www.example.com', '/')
Net::HTTP.get('www.example2.com', '/')
expect(stub).to have_been_requested.times(2)
expect(stub2).to have_been_requested.times(1)
WebMock.reset_executed_requests!
expect(stub).not_to have_been_requested
expect(stub2).not_to have_been_requested
```
## Disabling and enabling WebMock or only some http client adapters
```ruby
# Disable WebMock (all adapters)
WebMock.disable!
# Disable WebMock for all libs except Net::HTTP
WebMock.disable!(except: [:net_http])
# Enable WebMock (all adapters)
WebMock.enable!
# Enable WebMock for all libs except Patron
WebMock.enable!(except: [:patron])
```
## Matching requests
An executed request matches stubbed request if it passes following criteria:
- When request URI matches stubbed request URI string, Regexp pattern or RFC 6570 URI Template
- And request method is the same as stubbed request method or stubbed request method is :any
- And request body is the same as stubbed request body or stubbed request body is not specified
- And request headers match stubbed request headers, or stubbed request headers match a subset of request headers, or stubbed request headers are not specified
- And request matches provided block or block is not provided
## Precedence of stubs
Always the last declared stub matching the request will be applied i.e:
```ruby
stub_request(:get, "www.example.com").to_return(body: "abc")
stub_request(:get, "www.example.com").to_return(body: "def")
Net::HTTP.get('www.example.com', '/') # ====> "def"
```
## Matching URIs
WebMock will match all different representations of the same URI.
I.e all the following representations of the URI are equal:
```ruby
"www.example.com"
"www.example.com/"
"www.example.com:80"
"www.example.com:80/"
"http://www.example.com"
"http://www.example.com/"
"http://www.example.com:80"
"http://www.example.com:80/"
```
The following URIs with userinfo are also equal for WebMock
```ruby
"a b:pass@www.example.com"
"a b:pass@www.example.com/"
"a b:pass@www.example.com:80"
"a b:pass@www.example.com:80/"
"http://a b:pass@www.example.com"
"http://a b:pass@www.example.com/"
"http://a b:pass@www.example.com:80"
"http://a b:pass@www.example.com:80/"
"a%20b:pass@www.example.com"
"a%20b:pass@www.example.com/"
"a%20b:pass@www.example.com:80"
"a%20b:pass@www.example.com:80/"
"http://a%20b:pass@www.example.com"
"http://a%20b:pass@www.example.com/"
"http://a%20b:pass@www.example.com:80"
"http://a%20b:pass@www.example.com:80/"
```
or these
```ruby
"www.example.com/my path/?a=my param&b=c"
"www.example.com/my%20path/?a=my%20param&b=c"
"www.example.com:80/my path/?a=my param&b=c"
"www.example.com:80/my%20path/?a=my%20param&b=c"
"http://www.example.com/my path/?a=my param&b=c"
"http://www.example.com/my%20path/?a=my%20param&b=c"
"http://www.example.com:80/my path/?a=my param&b=c"
"http://www.example.com:80/my%20path/?a=my%20param&b=c"
```
If you provide Regexp to match URI, WebMock will try to match it against every valid form of the same url.
I.e `/my path/` will match `www.example.com/my%20path` because it is equivalent of `www.example.com/my path`
## Matching with URI Templates
If you use [Addressable::Template](https://github.com/sporkmonger/addressable#uri-templates) for matching, then WebMock will defer the matching rules to Addressable, which complies with [RFC 6570](http://tools.ietf.org/html/rfc6570).
If you use any of the WebMock methods for matching query params, then Addressable will be used to match the base URI and WebMock will match the query params. If you do not, then WebMock will let Addressable match the full URI.
## Matching headers
WebMock will match request headers against stubbed request headers in the following situations:
1. Stubbed request has headers specified and request headers are the same as stubbed headers
i.e stubbed headers: `{ 'Header1' => 'Value1', 'Header2' => 'Value2' }`, requested: `{ 'Header1' => 'Value1', 'Header2' => 'Value2' }`
2. Stubbed request has headers specified and stubbed request headers are a subset of request headers
i.e stubbed headers: `{ 'Header1' => 'Value1' }`, requested: `{ 'Header1' => 'Value1', 'Header2' => 'Value2' }`
3. Stubbed request has no headers
i.e stubbed headers: `nil`, requested: `{ 'Header1' => 'Value1', 'Header2' => 'Value2' }`
WebMock normalises headers and treats all forms of same headers as equal:
i.e the following two sets of headers are equal:
`{ "Header1" => "value1", content_length: 123, X_CuStOm_hEAder: :value }`
`{ header1: "value1", "Content-Length" => 123, "x-cuSTOM-HeAder" => "value" }`
## Recording real requests and responses and replaying them later
To record your application's real HTTP interactions and replay them later in tests you can use [VCR](https://github.com/vcr/vcr) with WebMock.
## Request callbacks
#### WebMock can invoke callbacks stubbed or real requests:
```ruby
WebMock.after_request do |request_signature, response|
puts "Request #{request_signature} was made and #{response} was returned"
end
```
#### invoke callbacks for real requests only and except requests made with Patron
```ruby
WebMock.after_request(except: [:patron],
real_requests_only: true) do |req_signature, response|
puts "Request #{req_signature} was made and #{response} was returned"
end
```
## Bugs and Issues
Please submit them here [http://github.com/bblimke/webmock/issues](http://github.com/bblimke/webmock/issues)
## Issue triage [](https://www.codetriage.com/bblimke/webmock)
You can contribute by triaging issues which may include reproducing bug reports or asking for vital information, such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to [subscribe to webmock on CodeTriage](https://www.codetriage.com/bblimke/webmock).
## Suggestions
If you have any suggestions on how to improve WebMock please send an email to the mailing list [groups.google.com/group/webmock-users](http://groups.google.com/group/webmock-users)
I'm particularly interested in how the DSL could be improved.
## Development
In order to work on Webmock you first need to fork and clone the repo.
Please do any work on a dedicated branch and rebase against master
before sending a pull request.
## Credits
The initial lines of this project were written during New Bamboo [Hack Day](http://blog.new-bamboo.co.uk/2009/11/13/hackday-results)
Thanks to my fellow [Bambinos](http://new-bamboo.co.uk/) for all the great suggestions!
People who submitted patches and new features or suggested improvements. Many thanks to these people:
* Ben Pickles
* Mark Evans
* Ivan Vega
* Piotr Usewicz
* Nick Plante
* Nick Quaranto
* Diego E. "Flameeyes" Pettenò
* Niels Meersschaert
* Mack Earnhardt
* Arvicco
* Sergio Gil
* Jeffrey Jones
* Tekin Suleyman
* Tom Ward
* Nadim Bitar
* Myron Marston
* Sam Phillips
* Jose Angel Cortinas
* Razic
* Steve Tooke
* Nathaniel Bibler
* Martyn Loughran
* Muness Alrubaie
* Charles Li
* Ryan Bigg
* Pete Higgins
* Hans de Graaff
* Alastair Brunton
* Sam Stokes
* Eugene Bolshakov
* James Conroy-Finn
* Salvador Fuentes Jr
* Alex Rothenberg
* Aidan Feldman
* Steve Hull
* Jay Adkisson
* Zach Dennis
* Nikita Fedyashev
* Lin Jen-Shin
* David Yeu
* Andreas Garnæs
* Roman Shterenzon
* Chris McGrath
* Stephen Celis
* Eugene Pimenov
* Albert Llop
* Christopher Pickslay
* Tammer Saleh
* Nicolas Fouché
* Joe Van Dyk
* Mark Abramov
* Frank Schumacher
* Dimitrij Denissenko
* Marnen Laibow-Koser
* Evgeniy Dolzhenko
* Nick Recobra
* Jordan Elver
* Joe Karayusuf
* Paul Cortens
* jugyo
* aindustries
* Eric Oestrich
* erwanlr
* Ben Bleything
* Jon Leighton
* Ryan Schlesinger
* Julien Boyer
* Kevin Glowacz
* Hans Hasselberg
* Andrew France
* Jonathan Hyman
* Rex Feng
* Pavel Forkert
* Jordi Massaguer Pla
* Jake Benilov
* Tom Beauvais
* Mokevnin Kirill
* Alex Grant
* Lucas Dohmen
* Bastien Vaucher
* Joost Baaij
* Joel Chippindale
* Murahashi Sanemat Kenichi
* Tim Kurvers
* Ilya Vassilevsky
* gotwalt
* Leif Bladt
* Alex Tomlins
* Mitsutaka Mimura
* Tomy Kaira
* Daniel van Hoesel
* Ian Asaff
* Ian Lesperance
* Matthew Horan
* Dmitry Gutov
* Florian Dütsch
* Manuel Meurer
* Brian D. Burns
* Riley Strong
* Tamir Duberstein
* Stefano Uliari
* Alex Stupakov
* Karen Wang
* Matt Burke
* Jon Rowe
* Aleksey V. Zapparov
* Praveen Arimbrathodiyil
* Bo Jeanes
* Matthew Conway
* Rob Olson
* Max Lincoln
* Oleg Gritsenko
* Hwan-Joon Choi
* SHIBATA Hiroshi
* Caleb Thompson
* Theo Hultberg
* Pablo Jairala
* Insoo Buzz Jung
* Carlos Alonso Pérez
* trlorenz
* Alexander Simonov
* Thorbjørn Hermanse
* Mark Lorenz
* tjsousa
* Tasos Stathopoulos
* Dan Buettner
* Sven Riedel
* Mark Lorenz
* Dávid Kovács
* fishermand46
* Franky Wahl
* ChaYoung You
* Simon Russell
* Steve Mitchell
* Mattias Putman
* Zachary Anker
* Emmanuel Sambo
* Ramon Tayag
* Johannes Schlumberger
* Siôn Le Roux
* Matt Palmer
* Zhao Wen
* Krzysztof Rygielski
* Magne Land
* yurivm
* Mike Knepper
* Charles Pence
* Alexey Zapparov
* Pablo Brasero
* Cedric Pimenta
* Michiel Karnebeek
* Alex Kestner
* Manfred Stienstra
* Tim Diggins
* Gabriel Chaney
* Chris Griego
* Taiki Ono
* Jonathan Schatz
* Jose Luis Honorato
* Aaron Kromer
* Pavel Jurašek
* Jake Worth
* Gabe Martin-Dempesy
* Michael Grosser
* Aleksei Maridashvili
* Ville Lautanala
* Koichi ITO
* Jordan Harband
* Tarmo Tänav
* Joe Marty
* Chris Thomson
* Vít Ondruch
* George Ulmer
* Christof Koenig
* Chung-Yi Chi
* Olexandr Hoshylyk
* Janko Marohnić
* Pat Allan
* Rick Song
* NARUSE, Yui
* Piotr Boniecki
* Olia Kremmyda
* Michał Matyas
* Matt Brictson
* Kenny Ortmann
* redbar0n
* Lukas Pokorny
* Arkadiy Tetelman
* Kazato Sugimoto
* Olle Jonsson
* Pavel Rosický
* Geremia Taglialatela
* Koichi Sasada
* Yusuke Endoh
* Grey Baker
* SoonKhen OwYong
* Pavel Valena
* Adam Sokolnicki
* Jeff Felchner
* Eike Send
* Claudio Poli
* Csaba Apagyi
* Frederick Cheung
* Fábio D. Batista
* Andriy Yanko
* y-yagi
* Rafael França
* George Claghorn
* Alex Junger
* Orien Madgwick
* Andrei Sidorov
* Marco Costa
* Ryan Davis
* Brandur
* Samuel Williams
* Patrik Ragnarsson
* Alex Coomans
* Vesa Laakso
* John Hawthorn
* guppy0356
* Thilo Rusche
* Andrew Stuntz
* Lucas Uyezu
* Bruno Sutic
* Ryan Kerr
* Adam Harwood
* Ben Koshy
* Jesse Bowes
* Marek Kasztelnik
* ce07c3
* Jun Jiang
* Oleksiy Kovyrin
* Matt Larraz
* Tony Schneider
* Niklas Hösl
* Johanna Hartmann
* Alex Vondrak
* Will Storey
* Eduardo Hernandez
* ojab
* Giorgio Gambino
* Timmitry
* Michael Fairley
* Ray Zane
* Go Sueyoshi
* Cedric Sohrauer
* Akira Matsuda
* Mark Spangler
For a full list of contributors you can visit the
[contributors](https://github.com/bblimke/webmock/contributors) page.
## Background
Thank you Fakeweb! This library was inspired by [FakeWeb](https://github.com/chrisk/fakeweb).
I imported some solutions from that project to WebMock. I also copied some code i.e Net:HTTP adapter.
Fakeweb architecture unfortunately didn't allow me to extend it easily with the features I needed.
I also preferred some things to work differently i.e request stub precedence.
## Copyright
Copyright (c) 2009-2010 Bartosz Blimke. See LICENSE for details.
webmock-3.18.1/minitest/ 0000755 0000041 0000041 00000000000 14333126774 015131 5 ustar www-data www-data webmock-3.18.1/minitest/test_webmock.rb 0000644 0000041 0000041 00000000435 14333126774 020146 0 ustar www-data www-data require File.expand_path(File.dirname(__FILE__) + '/test_helper')
require File.expand_path(File.dirname(__FILE__) + '/../test/shared_test')
test_class = defined?(MiniTest::Test) ? MiniTest::Test : MiniTest::Unit::TestCase
class MiniTestWebMock < test_class
include SharedTest
end
webmock-3.18.1/minitest/webmock_spec.rb 0000644 0000041 0000041 00000004365 14333126774 020127 0 ustar www-data www-data require File.expand_path(File.dirname(__FILE__) + '/test_helper')
describe "Webmock" do
include HttpRequestTestHelper
before do
@stub_http = stub_http_request(:any, "http://www.example.com")
@stub_https = stub_http_request(:any, "https://www.example.com")
end
it "should update assertions count" do
assert_equal 0, assertions
http_request(:get, "http://www.example.com/")
assert_requested(@stub_http)
assert_equal 2, assertions
assert_not_requested(:post, "http://www.example.com")
assert_equal 4, assertions
end
it "should raise error on non stubbed request" do
expect { http_request(:get, "http://www.example.net/") }.must_raise(WebMock::NetConnectNotAllowedError)
end
it "should verify that expected request occured" do
http_request(:get, "http://www.example.com/")
assert_requested(:get, "http://www.example.com", times: 1)
assert_requested(:get, "http://www.example.com")
end
it "should verify that expected http stub occured" do
http_request(:get, "http://www.example.com/")
assert_requested(@stub_http, times: 1)
assert_requested(@stub_http)
end
it "should verify that expected https stub occured" do
http_request(:get, "https://www.example.com/")
http_request(:get, "https://www.example.com/")
assert_requested(@stub_https, times: 2)
end
it "should verify that expect request didn't occur" do
expected_message = "The request GET http://www.example.com/ was expected to execute 1 time but it executed 0 times"
expected_message += "\n\nThe following requests were made:\n\nNo requests were made.\n============================================================"
assert_fail(expected_message) do
assert_requested(:get, "http://www.example.com")
end
end
it "should verify that expect stub didn't occur" do
expected_message = "The request ANY http://www.example.com/ was expected to execute 1 time but it executed 0 times"
expected_message += "\n\nThe following requests were made:\n\nNo requests were made.\n============================================================"
assert_fail(expected_message) do
assert_requested(@stub_http)
end
end
end
webmock-3.18.1/minitest/test_helper.rb 0000644 0000041 0000041 00000001437 14333126774 020001 0 ustar www-data www-data require 'rubygems'
$LOAD_PATH.unshift(File.dirname(__FILE__))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
require File.expand_path(File.dirname(__FILE__) + '/../test/http_request')
gem 'minitest'
require 'minitest/autorun'
require 'webmock/minitest'
test_class = defined?(MiniTest::Test) ? MiniTest::Test : MiniTest::Unit::TestCase
test_class.class_eval do
def assert_raise(*exp, &block)
assert_raises(*exp, &block)
end
def assert_raise_with_message(e, message, &block)
e = assert_raises(e, &block)
if message.is_a?(Regexp)
assert_match(message, e.message)
else
assert_equal(message, e.message)
end
end
def assert_fail(message, &block)
assert_raise_with_message(MiniTest::Assertion, message, &block)
end
end
webmock-3.18.1/spec/ 0000755 0000041 0000041 00000000000 14333126774 014227 5 ustar www-data www-data webmock-3.18.1/spec/quality_spec.rb 0000644 0000041 0000041 00000005362 14333126774 017264 0 ustar www-data www-data require "spec_helper"
# Borrowed from Bundler
# https://github.com/carlhuda/bundler/blob/1-0-stable/spec/quality_spec.rb
# Portions copyright (c) 2010 Andre Arko
# Portions copyright (c) 2009 Engine Yard
# MIT License
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
describe "The library itself" do
def check_for_tab_characters(filename)
failing_lines = []
File.readlines(filename).each_with_index do |line,number|
failing_lines << number + 1 if line =~ /\t/
end
unless failing_lines.empty?
"#{filename} has tab characters on lines #{failing_lines.join(', ')}"
end
end
def check_for_extra_spaces(filename)
failing_lines = []
File.readlines(filename).each_with_index do |line,number|
next if line =~ /^\s+#.*\s+\n$/
failing_lines << number + 1 if line =~ /\s+\n$/
end
unless failing_lines.empty?
"#{filename} has spaces on the EOL on lines #{failing_lines.join(', ')}"
end
end
RSpec::Matchers.define :be_well_formed do
failure_message do |actual|
actual.join("\n")
end
match do |actual|
actual.empty?
end
end
it "has no malformed whitespace" do
error_messages = []
Dir.chdir(File.expand_path("../..", __FILE__)) do
`git ls-files`.split("\n").each do |filename|
next if filename =~ /\.gitmodules|fixtures/
error_messages << check_for_tab_characters(filename)
error_messages << check_for_extra_spaces(filename)
end
end
expect(error_messages.compact).to be_well_formed
end
it "can still be built" do
Dir.chdir(File.expand_path('../../', __FILE__)) do
`gem build webmock.gemspec`
expect($?).to eq(0)
# clean up the .gem generated
system("rm webmock-#{WebMock.version}.gem")
end
end
end
webmock-3.18.1/spec/fixtures/ 0000755 0000041 0000041 00000000000 14333126774 016100 5 ustar www-data www-data webmock-3.18.1/spec/fixtures/test.txt 0000644 0000041 0000041 00000000005 14333126774 017613 0 ustar www-data www-data test
webmock-3.18.1/spec/acceptance/ 0000755 0000041 0000041 00000000000 14333126774 016315 5 ustar www-data www-data webmock-3.18.1/spec/acceptance/typhoeus/ 0000755 0000041 0000041 00000000000 14333126774 020175 5 ustar www-data www-data webmock-3.18.1/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb 0000644 0000041 0000041 00000010531 14333126774 024603 0 ustar www-data www-data require 'spec_helper'
require 'acceptance/webmock_shared'
unless RUBY_PLATFORM =~ /java/
require 'acceptance/typhoeus/typhoeus_hydra_spec_helper'
describe "Typhoeus::Hydra" do
include TyphoeusHydraSpecHelper
let(:hydra) { Typhoeus::Hydra.new }
before do
Typhoeus::Expectation.clear
end
include_context "with WebMock"
describe "Typhoeus::Hydra features" do
before(:each) do
WebMock.disable_net_connect!
WebMock.reset!
end
describe "supposed response fields" do
it "present" do
stub_request(:get, "http://www.example.com").to_return(headers: {'X-Test' => '1'})
response = Typhoeus.get("http://www.example.com")
expect(response.code).not_to be_nil
expect(response.status_message).not_to be_nil
expect(response.body).not_to be_nil
expect(response.headers).not_to be_nil
expect(response.effective_url).not_to be_nil
end
end
describe "when params are used" do
it "should take into account params for POST request" do
stub_request(:post, "www.example.com/?hello=world").with(query: {hello: 'world'})
request = Typhoeus::Request.new("http://www.example.com", method: :post, params: {hello: 'world'})
hydra.queue(request)
hydra.run
end
it "should take into account body for POST request" do
stub_request(:post, "www.example.com").with(body: {hello: 'world'})
response = Typhoeus.post("http://www.example.com", method: :post, body: {hello: 'world'})
expect(response.code).to eq(200)
end
it "should take into account params for GET request" do
stub_request(:get, "http://www.example.com/?hello=world").to_return({})
request = Typhoeus::Request.new("http://www.example.com/?hello=world", method: :get)
hydra.queue(request)
hydra.run
end
end
describe "timeouts" do
it "should support native typhoeus timeouts" do
stub_request(:any, "example.com").to_timeout
request = Typhoeus::Request.new("http://example.com", method: :get)
hydra.queue(request)
hydra.run
expect(request.response).to be_timed_out
end
end
describe "callbacks" do
before(:each) do
@request = Typhoeus::Request.new("http://example.com")
end
it "should call on_complete with 2xx response" do
body = "on_success fired"
stub_request(:any, "example.com").to_return(body: body)
test = nil
Typhoeus.on_complete do |c|
test = c.body
end
hydra.queue @request
hydra.run
expect(test).to eq(body)
end
it "should call on_complete with 5xx response" do
response_code = 599
stub_request(:any, "example.com").to_return(status: [response_code, "Server On Fire"])
test = nil
Typhoeus.on_complete do |c|
test = c.code
end
hydra.queue @request
hydra.run
expect(test).to eq(response_code)
end
it "should call on_body with 2xx response" do
body = "on_body fired"
stub_request(:any, "example.com").to_return(body: body)
test_body = nil
test_complete = nil
skip("This test requires a newer version of Typhoeus") unless @request.respond_to?(:on_body)
@request.on_body do |body_chunk, response|
test_body = body_chunk
end
@request.on_complete do |response|
test_complete = response.body
end
hydra.queue @request
hydra.run
expect(test_body).to eq(body)
expect(test_complete).to eq("")
end
it "should call on_headers with 2xx response" do
body = "on_headers fired"
stub_request(:any, "example.com").to_return(body: body, headers: {'X-Test' => '1'})
test_headers = nil
skip("This test requires a newer version of Typhoeus") unless @request.respond_to?(:on_headers)
@request.on_headers do |response|
test_headers = response.headers
end
hydra.queue @request
hydra.run
expect(test_headers.to_h).to include('X-Test' => '1')
end
end
end
end
end
webmock-3.18.1/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb 0000644 0000041 0000041 00000002671 14333126774 026150 0 ustar www-data www-data require 'ostruct'
module TyphoeusHydraSpecHelper
class FakeTyphoeusHydraTimeoutError < StandardError; end
class FakeTyphoeusHydraConnectError < StandardError; end
def http_request(method, uri, options = {}, &block)
uri = uri.gsub(" ", "%20") #typhoeus doesn't like spaces in the uri
request_options = {
method: method,
body: options[:body],
headers: options[:headers],
timeout: 25000
}
if options[:basic_auth]
request_options[:userpwd] = options[:basic_auth].join(':')
end
request = Typhoeus::Request.new(uri, request_options)
hydra = Typhoeus::Hydra.new
hydra.queue(request)
hydra.run
response = request.response
raise FakeTyphoeusHydraConnectError.new if response.return_code == :couldnt_connect
raise FakeTyphoeusHydraTimeoutError.new if response.timed_out?
OpenStruct.new({
body: response.body,
headers: WebMock::Util::Headers.normalize_headers(join_array_values(response.headers)),
status: response.code.to_s,
message: response.status_message
})
end
def join_array_values(hash)
joined = {}
if hash
hash.each do |k,v|
v = v.join(", ") if v.is_a?(Array)
joined[k] = v
end
end
joined
end
def client_timeout_exception_class
FakeTyphoeusHydraTimeoutError
end
def connection_refused_exception_class
FakeTyphoeusHydraConnectError
end
def http_library
:typhoeus
end
end
webmock-3.18.1/spec/acceptance/webmock_shared.rb 0000644 0000041 0000041 00000002617 14333126774 021625 0 ustar www-data www-data require 'spec_helper'
require 'acceptance/shared/enabling_and_disabling_webmock'
require 'acceptance/shared/returning_declared_responses'
require 'acceptance/shared/callbacks'
require 'acceptance/shared/request_expectations'
require 'acceptance/shared/stubbing_requests'
require 'acceptance/shared/allowing_and_disabling_net_connect'
require 'acceptance/shared/precedence_of_stubs'
require 'acceptance/shared/complex_cross_concern_behaviors'
unless defined? SAMPLE_HEADERS
SAMPLE_HEADERS = { "Content-Length" => "8888", "Accept" => "application/json" }
ESCAPED_PARAMS = "x=ab%20c&z=%27Stop%21%27%20said%20Fred%20m"
NOT_ESCAPED_PARAMS = "z='Stop!' said Fred m&x=ab c"
end
shared_examples "with WebMock" do |*adapter_info|
describe "with WebMock" do
let(:webmock_server_url) {"http://#{WebMockServer.instance.host_with_port}/"}
before(:each) do
WebMock.disable_net_connect!
WebMock.reset!
end
include_context "allowing and disabling net connect", *adapter_info
include_context "stubbing requests", *adapter_info
include_context "declared responses", *adapter_info
include_context "precedence of stubs", *adapter_info
include_context "request expectations", *adapter_info
include_context "callbacks", *adapter_info
include_context "enabled and disabled webmock", *adapter_info
include_context "complex cross-concern behaviors", *adapter_info
end
end
webmock-3.18.1/spec/acceptance/shared/ 0000755 0000041 0000041 00000000000 14333126774 017563 5 ustar www-data www-data webmock-3.18.1/spec/acceptance/shared/complex_cross_concern_behaviors.rb 0000644 0000041 0000041 00000002463 14333126774 026546 0 ustar www-data www-data shared_context "complex cross-concern behaviors" do |*adapter_info|
it 'allows a response with multiple values for the same header to be recorded and played back exactly as-is' do
WebMock.allow_net_connect!
recorded_response = nil
WebMock.after_request { |_,r| recorded_response = r }
real_response = http_request(:get, webmock_server_url)
stub_request(:get, webmock_server_url).to_return(
status: recorded_response.status,
body: recorded_response.body,
headers: recorded_response.headers
)
played_back_response = http_request(:get, webmock_server_url)
expect(played_back_response.headers.keys).to include('Set-Cookie')
expect(played_back_response).to eq(real_response)
end
let(:no_content_url) { 'https://httpstat.us/204' }
[nil, ''].each do |stub_val|
it "returns the same value (nil or "") for a request stubbed as #{stub_val.inspect} that a real empty response has", net_connect: true do
unless http_library == :curb
WebMock.allow_net_connect!
real_response = http_request(:get, no_content_url)
stub_request(:get, no_content_url).to_return(status: 204, body: stub_val)
stubbed_response = http_request(:get, no_content_url)
expect(stubbed_response.body).to eq(real_response.body)
end
end
end
end
webmock-3.18.1/spec/acceptance/shared/stubbing_requests.rb 0000644 0000041 0000041 00000075615 14333126774 023676 0 ustar www-data www-data # encoding: utf-8
shared_examples_for "stubbing requests" do |*adapter_info|
describe "when requests are stubbed" do
describe "based on uri" do
it "should return stubbed response even if request have escaped parameters" do
stub_request(:get, "www.example.com/hello+/?#{NOT_ESCAPED_PARAMS}").to_return(body: "abc")
expect(http_request(:get, "http://www.example.com/hello%2B/?#{ESCAPED_PARAMS}").body).to eq("abc")
end
it "should return stubbed response even if query params have integer values" do
stub_request(:get, "www.example.com").with(query: {"a" => 1}).to_return(body: "abc")
expect(http_request(:get, "http://www.example.com/?a=1").body).to eq("abc")
end
it "should return stubbed response even if request has non escaped params" do
stub_request(:get, "www.example.com/hello%2B/?#{ESCAPED_PARAMS}").to_return(body: "abc")
expect(http_request(:get, "http://www.example.com/hello+/?#{NOT_ESCAPED_PARAMS}").body).to eq("abc")
end
it "should return stubbed response for url with non utf query params" do
param = 'aäoöuü'.encode('iso-8859-1')
param = CGI.escape(param)
stub_request(:get, "www.example.com/?#{param}").to_return(body: "abc")
expect(http_request(:get, "http://www.example.com/?#{param}").body).to eq("abc")
end
it "should return stubbed response even if stub uri is declared as regexp and request params are escaped" do
stub_request(:get, /.*x=ab c.*/).to_return(body: "abc")
expect(http_request(:get, "http://www.example.com/hello/?#{ESCAPED_PARAMS}").body).to eq("abc")
end
it "should raise error specifying stubbing instructions with escaped characters in params if there is no matching stub" do
begin
http_request(:get, "http://www.example.com/hello+/?#{NOT_ESCAPED_PARAMS}")
rescue WebMock::NetConnectNotAllowedError => e
expect(e.message).to match(/Unregistered request: GET http:\/\/www\.example\.com\/hello\+\/\?x=ab%20c&z='Stop!'%20said%20Fred%20m/m)
expect(e.message).to match(/stub_request\(:get, "http:\/\/www\.example\.com\/hello\+\/\?x=ab%20c&z='Stop!'%20said%20Fred%20m"\)/m)
end
stub_request(:get, "http://www.example.com/hello+/?x=ab%20c&z='Stop!'%20said%20Fred%20m")
http_request(:get, "http://www.example.com/hello+/?#{NOT_ESCAPED_PARAMS}")
end
end
describe "based on query params" do
it "should return stubbed response when stub declares query params as a hash" do
stub_request(:get, "www.example.com").with(query: {"a" => ["b x", "c d"]}).to_return(body: "abc")
expect(http_request(:get, "http://www.example.com/?a[]=b+x&a[]=c%20d").body).to eq("abc")
end
it "should return stubbed response when stub declares query params as a hash" do
stub_request(:get, "www.example.com").with(query: "a[]=b&a[]=c").to_return(body: "abc")
expect(http_request(:get, "http://www.example.com/?a[]=b&a[]=c").body).to eq("abc")
end
it "should return stubbed response when stub declares query params both in uri and as a hash" do
stub_request(:get, "www.example.com/?x=3").with(query: {"a" => ["b", "c"]}).to_return(body: "abc")
expect(http_request(:get, "http://www.example.com/?x=3&a[]=b&a[]=c").body).to eq("abc")
end
it "should return stubbed response when stub expects only part of query params" do
stub_request(:get, "www.example.com").with(query: hash_including({"a" => ["b", "c"]})).to_return(body: "abc")
expect(http_request(:get, "http://www.example.com/?a[]=b&a[]=c&b=1").body).to eq("abc")
end
it 'should return stubbed response when stub expects exclude part of query params' do
stub_request(:get, 'www.example.com').with(query: hash_excluding(a: ['b', 'c'])).to_return(body: 'abc')
expect(http_request(:get, 'http://www.example.com/?a[]=c&a[]=d&b=1').body).to eq('abc')
end
it "should return stubbed response when stub expects an empty array" do
stub_request(:get, 'www.example.com').with(query: { a: [] }).to_return(body: 'abc')
expect(http_request(:get, 'http://www.example.com/?a[]').body).to eq('abc')
end
end
describe "based on method" do
it "should return stubbed response" do
stub_request(:get, "www.example.com")
expect(http_request(:get, "http://www.example.com/").status).to eq("200")
end
it "should match stubbed request when http request was made with method given as string" do
stub_request(:get, "www.example.com")
expect(http_request('get', "http://www.example.com/").status).to eq("200")
end
it "should raise error if stubbed request has different method" do
stub_request(:get, "www.example.com")
expect(http_request(:get, "http://www.example.com/").status).to eq("200")
expect {
http_request(:delete, "http://www.example.com/")
}.to raise_error(WebMock::NetConnectNotAllowedError, %r(Real HTTP connections are disabled. Unregistered request: DELETE http://www.example.com/)
)
end
end
describe "based on body" do
it "should match requests if body is the same" do
stub_request(:post, "www.example.com").with(body: "abc")
expect(http_request(
:post, "http://www.example.com/",
body: "abc").status).to eq("200")
end
it "should match requests if body is not set in the stub" do
stub_request(:post, "www.example.com")
expect(http_request(
:post, "http://www.example.com/",
body: "abc").status).to eq("200")
end
it "should not match requests if body is different" do
stub_request(:post, "www.example.com").with(body: "abc")
expect {
http_request(:post, "http://www.example.com/", body: "def")
}.to raise_error(WebMock::NetConnectNotAllowedError, %r(Real HTTP connections are disabled. Unregistered request: POST http://www.example.com/ with body 'def'))
end
describe "with regular expressions" do
it "should match requests if body matches regexp" do
stub_request(:post, "www.example.com").with(body: /\d+abc$/)
expect(http_request(
:post, "http://www.example.com/",
body: "123abc").status).to eq("200")
end
it "should not match requests if body doesn't match regexp" do
stub_request(:post, "www.example.com").with(body: /^abc/)
expect {
http_request(:post, "http://www.example.com/", body: "xabc")
}.to raise_error(WebMock::NetConnectNotAllowedError, %r(Real HTTP connections are disabled. Unregistered request: POST http://www.example.com/ with body 'xabc'))
end
end
describe "when body is declared as a hash" do
before(:each) do
stub_request(:post, "www.example.com").
with(body: {:a => '1', :b => 'five x', 'c' => {'d' => ['e', 'f']} })
end
describe "for request with url encoded body" do
it "should match request if hash matches body" do
expect(http_request(
:post, "http://www.example.com/",
body: 'a=1&c[d][]=e&c[d][]=f&b=five+x').status).to eq("200")
end
it "should match request if hash matches body in different order of params" do
expect(http_request(
:post, "http://www.example.com/",
body: 'a=1&c[d][]=e&b=five+x&c[d][]=f').status).to eq("200")
end
it "should not match if hash doesn't match url encoded body" do
expect {
http_request(
:post, "http://www.example.com/",
body: 'c[d][]=f&a=1&c[d][]=e')
}.to raise_error(WebMock::NetConnectNotAllowedError, %r(Real HTTP connections are disabled. Unregistered request: POST http://www.example.com/ with body 'c\[d\]\[\]=f&a=1&c\[d\]\[\]=e'))
end
describe "for request with form url encoded body and content type" do
it "should match if stubbed request body hash has string values matching string values in request body" do
WebMock.reset!
stub_request(:post, "www.example.com").with(body: {"foo" => '1'})
expect(http_request(
:post, "http://www.example.com/", headers: {'Content-Type' => 'application/x-www-form-urlencoded'},
body: "foo=1").status).to eq("200")
end
it "should match if stubbed request body hash has NON string values matching string values in request body" do
WebMock.reset!
stub_request(:post, "www.example.com").with(body: {"foo" => 1})
expect(http_request(
:post, "http://www.example.com/", headers: {'Content-Type' => 'application/x-www-form-urlencoded'},
body: "foo=1").status).to eq("200")
end
it "should match if stubbed request body is hash_included" do
WebMock.reset!
stub_request(:post, "www.example.com").with(body: {"foo" => hash_including("bar" => '1')})
expect(http_request(
:post, "http://www.example.com/", headers: {'Content-Type' => 'application/x-www-form-urlencoded'},
body: "foo[bar]=1").status).to eq("200")
end
end
end
describe "for request with json body and content type is set to json" do
it "should match if hash matches body" do
expect(http_request(
:post, "http://www.example.com/", headers: {'Content-Type' => 'application/json'},
body: "{\"a\":\"1\",\"c\":{\"d\":[\"e\",\"f\"]},\"b\":\"five x\"}").status).to eq("200")
end
it "should match if hash matches body in different form" do
expect(http_request(
:post, "http://www.example.com/", headers: {'Content-Type' => 'application/json'},
body: "{\"a\":\"1\",\"b\":\"five x\",\"c\":{\"d\":[\"e\",\"f\"]}}").status).to eq("200")
end
it "should match if hash contains date string" do #Crack creates date object
WebMock.reset!
stub_request(:post, "www.example.com").
with(body: {"foo" => "2010-01-01"})
expect(http_request(
:post, "http://www.example.com/", headers: {'Content-Type' => 'application/json'},
body: "{\"foo\":\"2010-01-01\"}").status).to eq("200")
end
it "should match if any of the strings have spaces" do
WebMock.reset!
stub_request(:post, "www.example.com").with(body: {"foo" => "a b c"})
expect(http_request(
:post, "http://www.example.com/", headers: {'Content-Type' => 'application/json'},
body: "{\"foo\":\"a b c\"}").status).to eq("200")
end
it "should match if stubbed request body hash has NON string values matching NON string values in request body" do
WebMock.reset!
stub_request(:post, "www.example.com").with(body: {"foo" => 1})
expect(http_request(
:post, "http://www.example.com/", headers: {'Content-Type' => 'application/json'},
body: "{\"foo\":1}").status).to eq("200")
end
it "should not match if stubbed request body hash has string values matching NON string values in request body" do
WebMock.reset!
stub_request(:post, "www.example.com").with(body: {"foo" => '1'})
expect{http_request(
:post, "http://www.example.com/", headers: {'Content-Type' => 'application/json'},
body: "{\"foo\":1}") }.to raise_error(WebMock::NetConnectNotAllowedError)
end
it "should not match if stubbed request body hash has NON string values matching string values in request body" do
WebMock.reset!
stub_request(:post, "www.example.com").with(body: {"foo" => 1})
expect{http_request(
:post, "http://www.example.com/", headers: {'Content-Type' => 'application/json'},
body: "{\"foo\":\"1\"}") }.to raise_error(WebMock::NetConnectNotAllowedError)
end
end
describe "for request with xml body and content type is set to xml" do
before(:each) do
WebMock.reset!
stub_request(:post, "www.example.com").
with(body: { "opt" => {:a => '1', :b => 'five', 'c' => {'d' => ['e', 'f']} }})
end
it "should match if hash matches body" do
expect(http_request(
:post, "http://www.example.com/", headers: {'Content-Type' => 'application/xml'},
body: "
You have reached this web page by typing "example.com", "example.net", or "example.org" into your web browser.
These domain names are reserved for use in documentation and are not available for registration. See RFC 2606, Section 3.
webmock-3.18.1/spec/support/failures.rb 0000644 0000041 0000041 00000000310 14333126774 020074 0 ustar www-data www-data module Failures def fail() raise_error(RSpec::Expectations::ExpectationNotMetError) end def fail_with(message) raise_error(RSpec::Expectations::ExpectationNotMetError, message) end end webmock-3.18.1/spec/support/webmock_server.rb 0000644 0000041 0000041 00000002425 14333126774 021310 0 ustar www-data www-data require 'webrick' require 'logger' require 'singleton' class WebMockServer include Singleton attr_reader :port, :started def host_with_port "localhost:#{port}" end def concurrent unless RUBY_PLATFORM =~ /java/ @pid = Process.fork do yield end else Thread.new { yield } end end def start @started = true server = WEBrick::GenericServer.new(Port: 0, Logger: Logger.new("/dev/null")) server.logger.level = 0 @port = server.config[:Port] concurrent do ['TERM', 'INT'].each do |signal| trap(signal) do Thread.new do server.shutdown end end end server.start do |socket| socket.read(1) socket.puts <<-EOT.gsub(/^\s+\|/, '') |HTTP/1.1 200 OK\r |Date: Fri, 31 Dec 1999 23:59:59 GMT\r |Content-Type: text/html\r |Content-Length: 11\r |Set-Cookie: bar\r |Set-Cookie: foo\r |\r |hello world EOT end end loop do begin TCPSocket.new("localhost", port) sleep 0.1 break rescue Errno::ECONNREFUSED sleep 0.1 end end end def stop if @pid Process.kill('INT', @pid) end end end webmock-3.18.1/CHANGELOG.md 0000644 0000041 0000041 00000203652 14333126774 015116 0 ustar www-data www-data # Changelog # 3.18.1 * Reverted simplified connection handing in Net::HTTP adapter due to https://github.com/bblimke/webmock/issues/999 # 3.18.0 * Net::BufferedIO is not replaced anymore. Thanks to [Ray Zane](https://github.com/rzane) * Simplified connection handing in Net::HTTP adapter. Thanks to [Ray Zane](https://github.com/rzane) # 3.17.1 * Fixed Syntax Error Thanks to [Mark Spangler](https://github.com/mspangler) # 3.17.0 * Minimum required Ruby version is 2.3 Thanks to [Go Sueyoshi](https://github.com/sue445) * When using Net::HTTP, stubbed socket StubSocket#close and StubSocket#closed? behave more like the real sockets. Thanks to [Ray Zane](https://github.com/rzane) * Added `peeraddr`, `ssl_version` and `cipher` methods to stubbed sockets used by Net::HTTP. Thanks to [Ray Zane](https://github.com/rzane) * Added support for matching top-level array in JSON request body. E.g. ```` stub_request(:post, 'www.example.com').with(body: [{a: 1}]) ```` Thanks to [Cedric Sohrauer](https://github.com/cedrics) # 3.16.2 * Minimum required Ruby version is 2.0. # 3.16.0 (yanked) * Fix leaky file descriptors and reuse socket for persistent connections. Thanks to [Ray Zane](https://github.com/rzane) * Allow specifying for what URIs or hosts, Net::HTTP should connect on start. Thanks to [Ray Zane](https://github.com/rzane) # 3.15.2 * Minimum required Ruby version is 2.0. # 3.15.0 (yanked) * fixed async-http adapter on Windows Thanks to [Pavel Rosický](https://github.com/ahorek) * Support for http.rb >= 5.0.2 Thanks to [ojab](https://github.com/ojab) * Curb adapter supports headers with `:` character in the header value Thanks to [Giorgio Gambino](https://github.com/mrbuzz) * Support for matching body of JSON or application/x-www-form-urlencoded requests with content type header including charset. Thanks to [Timmitry](https://github.com/Timmitry) * Prevent double-wrapping http.rb features on non-stubbed requests Thanks to [Michael Fairley](https://github.com/michaelfairley) # 3.14.0 * Bump Addressable from 2.3.6 to 2.8.0 Thanks to [Eduardo Hernandez](https://github.com/EduardoGHdez) # 3.13.0 * Support http.rb 5.x Thanks to [Will Storey](https://github.com/horgh) # 3.12.2 * Fixed em-http-request adapter to avoid calling middleware twice. Thanks to [Alex Vondrak](https://github.com/ajvondrak) # 3.12.1 * Fixed handling of URIs with IPv6 addresses with square brackets when in Net::HTTP adapter. Thanks to [Johanna Hartmann](https://github.com/JohannaHartmann) # 3.12.0 * Added support for handling custom JSON and XML content types e.g. 'application/vnd.api+json' # 3.11.3 * Fixed async-http adapter to only considered requests as real if they are real. Thanks to Thanks to [Tony Schneider](https://github.com/tonywok) and [Samuel Williams](https://github.com/ioquatix) # 3.11.2 * Fix for Manticore streaming mode Thanks to [Oleksiy Kovyrin](https://github.com/kovyrin) # 3.11.1 * Compatibility with async-http 0.54+ Thanks to [Jun Jiang](https://github.com/jasl) # 3.11.0 * Added support for `features` in http.rb adapter. Thanks to [Carl (ce07c3)](https://github.com/ce07c3) # 3.10.0 * Added option to global stubs to have lower priority than local stubs. WebMock.globally_stub_request(:after_local_stubs) do { body: "global stub body" } end stub_request(:get, "www.example.com").to_return(body: 'non-global stub body') expect(http_request(:get, "http://www.example.com/").body).to eq("non-global stub body") Thanks to [Marek Kasztelnik](https://github.com/mkasztelnik) # 3.9.5 * Prevent overwriting `teardown` method in Test::Unit Thanks to [Jesse Bowes](https://github.com/jessebs) # 3.9.4 * More intuitive error message when stubbed response body was provided as Hash Thanks to [Ben Koshy](https://github.com/BKSpurgeon) # 3.9.3 * Make httpclient_adapter thread-safe Thanks to [Adam Harwood](https://github.com/adam-harwood) # 3.9.2 * Made global stubs thread-safe Thanks to [Adam Harwood](https://github.com/adam-harwood) # 3.9.1 * Fixed support for passing `URI` objects as second argument of `stub_request` Thanks to [Ryan Kerr](https://github.com/leboshi) ## 3.9.0 * Allow using a "callable" (like a proc) as URI pattern stub_request(:any, ->(uri) { true }) Thanks to [John Hawthorn](https://github.com/jhawthorn) * Added stubbed IO on stubbed socket in Net::HTTP adapter. Thanks to [Thilo Rusche](https://github.com/trusche) * When 'webmock/rspec' is required, reset WebMock after all after(:each/example) hooks Thanks to [Andrew Stuntz](https://github.com/drews256) * Fixed `net_connect_allowed?` when invoked with no arguments, when there were any allowed URIs passed to `disable_net_connect?`. Thanks to [Lucas Uyezu](https://github.com/lucasuyezu) * Fixed async-http adapter which caused Async::HTTP::Client or Async::HTTP::Internet to hang and never return a response. Thanks to [Bruno Sutic](https://github.com/bruno-) and [Samuel Williams](https://github.com/ioquatix) * Fixed warning when using async-http adapter Thanks to [Bruno Sutic](https://github.com/bruno-) * Dropped support for Ruby 2.3 - EOL date: 2019-03-31 * Dropped support for Ruby 2.4 - EOL date: 2020-03-31 * Handling matching of Addressable::Template patterns that have an ip address without port and patterns that have ip address and don’t have schema and path. Thanks to [Rafael França](https://github.com/rafaelfranca) and [guppy0356](https://github.com/guppy0356) ## 3.8.3 * Fixed problem introduced in version 3.4.2, which caused matching against Addressable::Template representing host part of the URI to raise an error. Thanks to [Vesa Laakso](https://github.com/valscion) ## 3.8.2 * Support correct encoding parameter for HTTP.rb 2.x and earlier Thanks to [Alex Coomans](https://github.com/drcapulet) ## 3.8.1 * Added support for mocking non-ASCII bodies when making requests with HTTP.rb Thanks to [Patrik Ragnarsson](https://github.com/dentarg) ## 3.8.0 * Fixed options handling when initialising Async::HTTP::Client Thanks to [Samuel Williams](https://github.com/ioquatix) * Ruby 2.7 support. Thanks to [Ryan Davis](https://github.com/zenspider) and [Brandur](https://github.com/brandur) ## 3.7.6 * Suppressed keyword argument warnings in Ruby 2.7 in async-http adapter. Thanks to [Koichi ITO](https://github.com/koic) ## 3.7.5 * Suppress Excon warning generated by extra key Thanks to [Marco Costa](https://github.com/marcotc) ## 3.7.4 * Resetting memoized response fields in Curb adapter. Thanks to [Andrei Sidorov](https://github.com/heretge) ## 3.7.3 * Fix for http.rb. Allow passing an output buffer to HTTP::Response::Body#readpartial Thanks to [George Claghorn](https://github.com/georgeclaghorn) * Fixed Manticore adapter to invoke Manticore failure handler on stubbed timeout Thanks to [Alex Junger](https://github.com/alexJunger) * Added project metadata to the gemspec Thanks to [Orien Madgwick](https://github.com/orien) ## 3.7.2 * Fixed handling of non UTF-8 encoded urls Thanks to [Rafael França](https://github.com/rafaelfranca) * Fixed "shadowing outer local variable" warning Thanks to [y-yagi](https://github.com/y-yagi) ## 3.7.1 * Fixed Async::HTTP::Client adapter code to not cause Ruby warning Thanks to [y-yagi](https://github.com/y-yagi) ## 3.7.0 * Support for Async::HTTP::Client Thanks to [Andriy Yanko](https://github.com/ayanko) ## 3.6.2 * Fixed Patron adapter to handle HTTP/2 status line. Thanks to [Fábio D. Batista](https://github.com/fabiob) ## 3.6.1 * Fixed issue with matching Addressable::Template without a period in the domain Thanks to [Eike Send](https://github.com/eikes) * Support for `write_timeout` in Net::HTTP Thanks to [Claudio Poli](https://github.com/masterkain) * Fixed issue with handling urls with ":80" or ":443" in the path. Thanks to [Csaba Apagyi](https://github.com/thisismydesign) for reporting and to [Frederick Cheung](https://github.com/fcheung) for fixing the issue. ## 3.6.0 * Compatibility with the latest version of hashdiff gem, with constant changed from HashDiff to Hashdiff Thanks to [Jeff Felchner](https://github.com/jfelchner) * Added a hint to the error message raised when `with` method is called without args or a block. Thanks to [Adam Sokolnicki](https://github.com/asok) * Resetting configured HTTP method in Curb adapter after each request Thanks to [tiendo1011](https://github.com/tiendo1011) * Added `WebMock.enable_net_connect!` as an alias for `WebMock.allow_net_connect!` and `WebMock.disallow_net_connect!` as an alias for `WebMock.disable_net_connect!` Thanks to [SoonKhen OwYong](https://github.com/owyongsk) * Fixed handling of empty arrays as query params when using Faraday Thanks to [Ryan Moret](https://github.com/rcmoret) ## 3.5.1 * Disabling TracePoint defined in Net::BufferedIO in case of exception being raised. Thanks to [Koichi Sasada](https://github.com/ko1) ## 3.5.0 * Ruby 2.6.0 support Thanks to [Arkadiy Tetelman](https://github.com/arkadiyt) * Added `WebMock.reset_executed_requests!` method. stub_get = stub_request(:get, "www.example.com") Net::HTTP.get('www.example.com', '/') WebMock::RequestRegistry.instance.times_executed(stub_get.request_pattern) # => 1 reset_executed_requests! WebMock::RequestRegistry.instance.times_executed(stub_get.request_pattern) # => 0 Thanks to [Olia Kremmyda](https://github.com/oliakremmyda) * Performance improvements Thanks to [Pavel Rosický](https://github.com/ahorek) ## 3.4.2 * Fixed `rbuf_fill` in Net::HTTP adapter to be thread-safe Thanks to [Arkadiy Tetelman](https://github.com/arkadiyt) * Fix invalid scheme error with Addressable::Template Thanks to [Kazato Sugimoto](https://github.com/uiureo) ## 3.4.1 * When comparing url encoded body to a body from request stub, which was declared as hash, only String, Numeric and boolean hash values are stringified before the comparison. Thanks to [Lukas Pokorny](https://github.com/luk4s) ## 3.4.0 * Ruby 2.6 support. Prevent `Net/ReadTimeout` error in Ruby 2.6 Thanks to [Koichi ITO](https://github.com/koic) * Handling query params, which represent nested hashes with keys starting with non word characters. Thanks to [rapides](https://github.com/rapides) for reporting the issue. * Patron adapter handles PATCH requests with body. Thanks to [Mattia](https://github.com/iMacTia) for reporting the issue. * Allowing requests with url encoded body to be matched by request stubs declared with hash body with non-string values. stub_request(:post, "www.example.com").with(body: {"a" => 1, "b" => false}) RestClient.post('www.example.com', 'a=1&b=false', :content_type => 'application/x-www-form-urlencoded') # ===> Success Thanks to [Kenny Ortmann](https://github.com/yairgo) for suggesting this feature. * When request headers contain 'Accept'=>'application/json' and no registered stub matches the request, WebMock prints a suggested stub code with to_return body set to '{}'. Thanks to [redbar0n](https://github.com/redbar0n) * Improved suggested stub output when the request stub only contains headers declaration. Thanks to [Olia Kremmyda](https://github.com/oliakremmyda) * Fixed Curb adapter to handle `reset` method. Thanks tp [dinhhuydh](https://github.com/dinhhuydh) for reporting the issue. Thanks to [Olia Kremmyda](https://github.com/oliakremmyda) for fixing it. ## 3.3.0 * Better formatting of outputted request stub snippets, displayed on failures due to unstubbed requests. Thanks to [Olia Kremmyda](https://github.com/oliakremmyda) ## 3.2.1 * Fixed Ruby warning under Ruby 2.5 Thanks to [Matt Brictson](https://github.com/mattbrictson) ## 3.2.0 * Automatically disable WebMock after Rspec suite Thanks to [Michał Matyas](https://github.com/d4rky-pl) * Fixed bug when handling redirection using Curb. Thanks to [Olia Kremmyda](https://github.com/oliakremmyda) ## 3.1.1 * Warning message is displayed only once when adding query params to URIAddressablePattern. ## 3.1.0 * http.rb 3.0.0 compatibility Thanks to [Piotr Boniecki](https://github.com/Bonias) * Typhoeus 1.3.0 support Thanks to [NARUSE, Yui](https://github.com/nurse) * Added support for matching partial query params using hash_excluding stub_request(:get, "www.example.com"). with(query: hash_excluding({"a" => "b"})) RestClient.get("http://www.example.com/?a=b") # ===> Failure RestClient.get("http://www.example.com/?a=c") # ===> Success Thanks to [Olexandr Hoshylyk](https://github.com/Warrior109) * Added MRI 2.3+ frozen string literal compatibility Thanks to [Pat Allan](https://github.com/pat) * Ensured that HTTPClient adapter does not yield block on empty response body if a block is provided Thanks to [NARUSE, Yui](https://github.com/nurse) * Fixed issue with `to_timeout` incorrectly raising `HTTP::ConnectionError` instead of `HTTP::TimeoutError` when using http.rb Thanks to [Rick Song](https://github.com/RickCSong) * Fixed problem with `response.connection.close` method being undefined when using http.rb Thanks to [Janko Marohnić](https://github.com/janko-m) * Fixed problem with matching Net::HTTP request header values assigned as numbers. Thanks to [Felipe Constantino de Oliveira](https://github.com/felipecdo) for reporting the issue. * Fixed problem with Net::HTTP adapter converting empty response body to nil for non 204 responses. Thanks to [Jeffrey Charles](https://github.com/jeffcharles) for reporting the issue. ## 3.0.1 * Suppressed \`warning: \`&' interpreted as argument prefix\` Thanks to [Koichi ITO](https://github.com/koic) ## 3.0.0 * Dropped support for Ruby 1.9.3 * Using Ruby >= 1.9 hash key syntax in stub suggestions Thanks to [Tarmo Tänav](https://github.com/tarmo) * Add at_least matchers for fakeweb-style expectations Thanks to [Joe Marty](https://github.com/mltsy) * Fix against "can't modify frozen String' error when Ruby option `frozen_string_literal` is enabled. Thanks to [Chris Thomson](https://github.com/christhomson) * Handling `read_timeout` option in Net::HTTP in Ruby >= 2.4 Thanks to [Christof Koenig](https://github.com/ckoenig) * `RequestRegistry` fix for `RuntimeError - can't add a new key into hash during iteration` Thanks to [Chung-Yi Chi](https://github.com/starsirius) ## 2.3.2 * Restored support for Ruby 1.9.3 to comply with semantic versioning. Thanks to [Jordan Harband](https://github.com/ljharb) for reporting the problem. ## 2.3.1 * Added support for Ruby 2.4 Thanks to [Koichi ITO](https://github.com/koic) * Dropped support for Ruby 1.9.3 ## 2.2.0 * Added `refute_requested` as an alias for `assert_not_requested` Thanks to [Michael Grosser](https://github.com/grosser) * Raising `Net::OpenTimeout` instead of `Timeout::Error` if available when a request stub is declared `to_timeout` Thanks to [Gabe Martin-Dempesy](https://github.com/gabetax) ## 2.1.1 * Added support for handling status messages in Excon responses. Thanks to [Tero Marttila](https://github.com/SpComb) for reporting the issue. ## 2.1.0 * Added support for `on_debug` callback in Curb. Thanks to [Pavel Jurašek](https://github.com/pavel-jurasek-bcgdv-com) * Added support for PATCH requests using Curb. Thanks to [Pavel Jurašek](https://github.com/pavel-jurasek-bcgdv-com) ## 2.0.3 * Handling headers passed as an Array to Curl::Easy Thanks to [Chelsea](https://github.com/grosscr) for reporting the issue. * Removed Ruby warnings. Thanks to [Aaron Kromer](https://github.com/cupakromer) ## 2.0.2 * Using `Base64.strict_encode64` instead of `Base64.encode64` to handle long user:pass basic auth credentials Thanks to [Jonathan Schatz](https://github.com/modosc) * Fixed handling of Authorisation header provided as string instead of array when using em-http-request. Thanks to [Michael Richardson](https://github.com/TTransmit) for reporing the issue. * Ensured `WebMock.net_connect_explicit_allowed?` always returns boolean. Thanks tp [Jose Luis Honorato](https://github.com/jlhonora) ## 2.0.1 * Added code responsible for loading em-http-request if available, which has been removed by mistake. Thanks to [Vasiliy](https://github.com/304) * WebMock loads "base64" if it's not yet loaded. Thanks to [Taiki Ono](https://github.com/taiki45). ## 2.0.0 * `require 'webmock'` does not enable WebMock anymore. `gem 'webmock'` can now be safely added to a Gemfile and no http client libs will be modified when it's loaded. Call `WebMock.enable!` to enable WebMock. Please note that `require 'webmock/rspec'`, `require 'webmock/test_unit'`, `require 'webmock/minitest'` and `require 'webmock/cucumber'` still do enable WebMock. * Dropped support for Ruby < 1.9.3 * Dropped support for em-http-request < 1.0.0 * WebMock 2.0 does not match basic authentication credentials in the userinfo part of the url, with credentials passed in `Authorization: Basic ...` header anymore. It now treats the Authorization header and credentials in the userinfo part of a url as two completely separate attributes of a request. The following stub declaration, which used to work in WebMock 1.x, is not going to work anymore stub_request(:get, "user:pass@www.example.com") Net::HTTP.start('www.example.com') do |http| req = Net::HTTP::Get.new('/') req.basic_auth 'user', 'pass' http.request(req) end # ===> Failure In order to stub a request with basic authentication credentials provided in the Authorization header, please use the following code: stub_request(:get, "www.example.com").with(basic_auth: ['user', 'pass']) or stub_request(:get, "www.example.com"). with(headers: 'Authorization' => "Basic #{ Base64.strict_encode64('user:pass').chomp}") In order to stub a request with basic authentication credentials provided in the url, please use the following code: stub_request(:get, "user:pass@www.example.com") RestClient.get('user:pass@www.example.com') # ===> Success ## 1.24.6 * Fixed issue with RUBY_VERSION comparison using old RubyGems. Thanks to [Chris Griego](https://github.com/cgriego). * Support for http.rb >= 2.0.0 ## 1.24.4 * Fixed the issue with parsing query to a hash with nested array i.e. `a[][b][]=one&a[][c][]=two` Thanks to [Tim Diggins](https://github.com/timdiggins) for reporting the issue. Thanks to [Cedric Pimenta](https://github.com/cedricpim) for finding the solution. ## 1.24.3 * Allow Net:HTTP headers keys to be provided as symbols if `RUBY_VERSION` >= 2.3.0 Thanks to [Alex Kestner](https://github.com/akestner) * Added a clear message on an attempt to match a multipart encoded request body. WebMock doesn't support requests with multipart body... yet. * `WebMock.disable_net_connect` `:allow` option, provided as regexp, matches https URIs correctly. * `WebMock.disable_net_connect` `:allow` option can be set as a url string with scheme, host and port. WebMock.disable_net_connect!(:allow => 'https://www.google.pl') Thanks to [Gabriel Chaney](https://github.com/gabrieljoelc) for reporting the issue. ## 1.24.2 * Improve parsing of params on request Thanks to [Cedric Pimenta](https://github.com/cedricpim) ## 1.24.1 * HTTPClient adapter supports reading basic authentication credentials directly from Authorization header. Thanks to [Michiel Karnebeek](https://github.com/mkarnebeek) ## 1.24.0 * Enabled support for Curb > 0.8.6 ## 1.23.0 * `WebMock.disable_net_connect` accepts `:allow` option with an object that responds to `#call`, receiving a `URI` object and returning a boolean: denylist = ['google.com', 'facebook.com', 'apple.com'] allowed_sites = lambda{|uri| denylist.none?{|site| uri.host.include?(site) } } WebMock.disable_net_connect!(:allow => allowed_sites) RestClient.get('www.example.org', '/') # ===> Allowed RestClient.get('www.facebook.com', '/') # ===> Failure RestClient.get('apple.com', '/') # ===> Failure Thanks to [Pablo Brasero](https://github.com/pablobm) * Support for HTTPClient stream responses with body chunks Thanks to [Cedric Pimenta](https://github.com/cedricpim) ## 1.22.6 * Fixes [issue](https://github.com/bblimke/webmock/issues/568) around WebMock restricting [Addressable](https://github.com/sporkmonger/addressable) version, based on Ruby 1.8.7 for all versions of Ruby. This change inverts that, and forces Ruby 1.8.7 users to specify in thier Gemfile an Addressable version < 2.4.0. Thanks to [PikachuEXE](https://github.com/PikachuEXE) and [Matthew Rudy Jacobs](https://github.com/matthewrudy). ## 1.22.5 * Fixes [bug](https://github.com/bblimke/webmock/issues/565) where WebMock tries to alias a method that is deprecated in Ruby Versions > 1.9.2 ('sysread' for class 'StringIO') Thanks to [Marcos Acosta](https://github.com/mmaa) for discovering this bug. ## 1.22.4 * Adds support for JSONClient (a subclass of HTTPClient) Thanks to [Andrew Kozin](https://github.com/nepalez) * Adds support for Ruby 2.3.0 Thanks to [Charles Pence](https://github.com/cpence) * Adds support for [http](https://github.com/httprb/http) versions >= 1.0.0 Thanks to [Alexey Zapparov](https://github.com/ixti) * Fixes support for Ruby 1.8.7 by restrciting Addressable version < 2.4.0 Thanks to [Matthew Rudy Jacobs](https://github.com/matthewrudy) ## 1.22.3 * Return "effective_url" attribute in Typhoeus::Response Thanks to [Senya](https://github.com/cmrd-senya) ## 1.22.2 * Fix: prevents adding an extra =true to urls with parameters without values Thanks to [David Begin](https://github.com/davidbegin) ## 1.22.1 * Adds Rack as a development dependency and removes require rack/utils in main lib. Thanks to [Keenan Brock](https://github.com/kbrock) ## 1.22.0 All the credit for preparing this release go to [David Begin](https://github.com/davidbegin)! * Adds [Manticore](https://github.com/cheald/manticore) support. Thanks to [Mike Knepper](https://github.com/mikeknep), [David Abdemoulaie](https://github.com/hobodave) * Update to Show a hash diff for requests that have stubs with a body. Thanks to [yurivm](https://github.com/yurivm) * Update to mirror Net::HTTP handling of headers as symbols * Update to ignore non-comparable-values error when sorting query values, because sorting is just a convience. Thanks to [Magne Land](https://github.com/magneland) * Covert Boolean values to Strings when using them to define the body of a request. Thanks to [Krzysztof Rygielski](https://github.com/riggy) * Fixes WebMock's parsing Multibyte characters Thanks to [Zhao Wen](https://github.com/VincentZhao) * Updates to be compatible with httpclient 2.6.0 * Converts keys from symbols to strings when for QueryMapper.to_query Thanks to [Ramon Tayag](https://github.com/ramontayag) * Restricts http.rb version to 0.7.3 for Ruby 1.8.7 * Fixes issue emulating em-http-request's handling of multiple requests. Thanks to [Matt Palmer](https://github.com/mpalmer) * WebMock requires only the necessary parts of crack to avoid pulling in safe_yaml Thanks to [Johannes Schlumberger](https://github.com/spjsschl) ## 1.21.0 * Support for http.rb >= 0.8.0 Thanks to [Zachary Anker](https://github.com/zanker), [Aleksey V. Zapparov](https://github.com/ixti) * Support for http.rb 0.7.0 Thanks to [Mattias Putman](https://github.com/challengee) * Added support for RSpec3-like `and_return`, `and_raise`, `and_timeout` syntax. Thanks to [Franky Wahl](https://github.com/frankywahl) * Restricted Curb support up to version 0.8.6. WebMock specs fail with Curb 0.8.7. ## 1.20.4 * Fixed support for `hash_including` matcher in RSpec 3 ## 1.20.3 * `with` method raises error if provided without options hash and without block * `with` and `to_return` raise an error if invoked with invalid keys in options hash. ## 1.20.2 * WebMock provides a helpful error message if an incompatible object is given as response body. Thanks to [Mark Lorenz](https://github.com/dapplebeforedawn) ## 1.20.1 * `assert_requested` and `assert_not_requested` accept `at_least_times` and `at_most_times` options Thanks to [Dan Buettner](https://github.com/Capncavedan) * Silenced `instance variable undefined` warnings in Curb adapted. Thanks to [Sven Riedel](https://github.com/sriedel) ## 1.20.0 * Add support for on_missing callback of Curb::Easy Thanks to [Tasos Stathopoulos](https://github.com/astathopoulos) * Add at_least_times and at_most_times matchers Thanks to [Dan Buettner](https://github.com/Capncavedan) ## 1.19.0 * Fixed issue with Excon adapter giving warning message when redirects middleware was enabled. Thanks to [Theo Hultberg](https://github.com/iconara) for reporting that. * Fixed issue with `undefined method 'valid_request_keys' for Excon::Utils:Module` Thanks to [Pablo Jairala](https://github.com/davidjairala) * Fixed query mapper to encode `'one' => ['1','2']` as `'one[]=1&one[]=2'`. Thanks to [Insoo Buzz Jung](https://github.com/insoul) * Improved cookies support for em-http-request Thanks to [Carlos Alonso Pérez](https://github.com/calonso) * Fix HTTP Gem adapter to ensure uri attribute is set on response object. Thanks to [Aleksey V. Zapparov](https://github.com/ixti) * Fixed HTTPClient adapter. The response header now receives `request_method`, `request_uri`, and `request_query` transferred from request header Thanks to [trlorenz](https://github.com/trlorenz) * Query mapper supports nested data structures i.e. `{"first" => [{"two" => [{"three" => "four"}, "five"]}]}` Thanks to [Alexander Simonov](https://github.com/simonoff) * Fixed compatibility with latest versions of Excon which don't define `VALID_REQUEST_KEYS` anymore. Thanks to [Pablo Jairala](https://github.com/davidjairala) * Request method is always a symbol is request signatures. This fixes the issue of WebMock not matching Typhoeus requests with request method defined as string. Thanks to [Thorbjørn Hermanse](https://github.com/thhermansen) * Stubbing instructions which are displayed when no matching stub is found, can be disabled with `Config.instance.show_stubbing_instructions = false` Thanks to [Mark Lorenz](https://github.com/dapplebeforedawn) * Notation used for mapping query strings to data structure can be configured i.e. `WebMock::Config.instance.query_values_notation = :subscript`. This allows setting `:flat_array` notation which supports duplicated parameter names in query string. Thanks to [tjsousa](https://github.com/tjsousa) ## 1.18.0 * Updated dependency on Addressable to versions >= 2.3.6 * Added support for matching uris using RFC 6570 (URI Templates) uri_template = Addressable::Template.new "www.example.com/{id}/" stub_request(:any, uri_template) Thanks to [Max Lincoln](https://github.com/maxlinc) * Fixed content length calculation for Rack responses with UTF8 body Thanks to [Oleg Gritsenko](https://github.com/Claster) * Add missing Curl::Easy aliases Thanks to [Hwan-Joon Choi](https://github.com/hc5duke) * HTTP Gem >= 0.6.0 compatibility Thanks to [Aleksey V. Zapparov](https://github.com/ixti) * Minitest 4 and 5 compatibility. Thanks to [SHIBATA Hiroshi](https://github.com/hsbt) ## 1.17.4 * Update matchers for RSpec 3's matcher protocol Thanks to [Rob Olson](https://github.com/robolson) ## 1.17.3 * Fixed issue with Rack response removing 'Content-Type' header Thanks to [Bo Jeanes](https://github.com/bjeanes) and [Matthew Conway](https://github.com/mattonrails) ## 1.17.2 * Support for chunked responses in Curb Thanks to [Zachary Belzer](https://github.com/zbelzer) * Fixed handling of request body passed as a hash to `Typhoeus.post` Thanks to [Mason Chang](https://github.com/changmason) for reporting. ## 1.17.1 * Added missing license statements. Thanks to [Praveen Arimbrathodiyil](https://github.com/pravi) ## 1.17.0 * HTTP gem support! Thanks to [Aleksey V. Zapparov](https://github.com/ixti) * Limited Excon gem requirement to version < 0.30 until the compatibility with version > 0.30.0 is fixed. Thanks to [Aleksey V. Zapparov](https://github.com/ixti) * Fixed issue where empty query key caused a `TypeError` Thanks to [Jon Rowe](https://github.com/JonRowe) * Handling Typhoeus `on_headers` and `on_body` params. Thanks to [Matt Burke](https://github.com/spraints) ## 1.16.1 * Fixed "NameError: uninitialized constant WebMock::Response::Pathname" issue. Thanks to [Alex Stupakow and Karen Wang](https://github.com/stupakov) for the fix. ## 1.16.0 * Allow a Pathname to be passed as a Response body stub_request(:get, /example.com/).to_return( body: Rails.root.join('test/fixtures/foo.txt') ) Thanks to [Ben Pickles](https://github.com/benpickles) * `hash_including` matcher can be initialized with empty keys to match any values. stub_request(:post, "www.example.com").with(:body => hash_including(:a, :b => {'c'})) RestClient.post('www.example.com', '{"a":"1","b":"c"}', :content_type => 'application/json') Thanks to [Stefano Uliari](https://github.com/steookk) ## 1.15.2 * Fixed `hash_including` to accept a splat of solitary keys. Thanks to [Tamir Duberstein](https://github.com/tamird) and [https://github.com/strongriley](https://github.com/strongriley) ## 1.15.0 * Excon >= 0.27.5 compatibility. Thanks to [Brian D. Burns](https://github.com/burns) ## 1.14.0 * Handling non UTF-8 characters in query params. Thanks to [Florian Dütsch](https://github.com/der-flo) for reporting the issue. * Added support for `request_block` param in Excon Thanks to [Dmitry Gutov](https://github.com/dgutov) for reporting the issue. * Fixed compatibility with latest Curb Thanks to [Ian Lesperance](https://github.com/elliterate) and [Matthew Horan](https://github.com/mhoran) * Triggering errbacks assynchronously in em-http-request adapter. Thanks to [Ian Lesperance](https://github.com/elliterate) and [Matthew Horan](https://github.com/mhoran) * Handling query params with a hashes nested inside arrays. Thanks to [Ian Asaff](https://github.com/montague) * Changed NetConnectNotAllowedError to inherit from Exception to allow it to bubble up into a test suite. Thanks to [Daniel van Hoesel](https://github.com/s0meone) * HTTPClient adapter is thread safe. Thanks to [Tom Beauvais](https://github.com/tbeauvais) ## 1.13.0 * Net::HTTP::Persistent compatibility. WebMock doesn't disconnect previously started connections upon a request anymore. ## 1.12.3 * Fixed issue with handling Addressable::URI with query params passed to `Net::HTTP.get_response` Thanks to [Leif Bladt](https://github.com/leifbladt) * Fixed HTTPClient adapter to not raise an error if a request with multipart body is executed. ## 1.12.2 * Fixed issue with handling request.path when Addressable::URI is passed to #request instead of URI with Ruby 2.0. Thanks to [Leif Bladt](https://github.com/leifbladt) * Accept integers as query param values in request stubs i.e. `stub_request(:get, /.*/).with(:query => {"a" => 1})` Thanks to [Mitsutaka Mimura](https://github.com/takkanm) ## 1.12.1 * Fixed Minitest < 5.0 compatibility Thanks to [Alex Tomlins](https://github.com/alext) for reporting the issue. ## 1.12.0 * Not using Gem spec anymore to check loaded Curb version. * `WebMock.disable_net_connect!` now accepts array of regexps as allow param: i.e. `WebMock.disable_net_connect!(:allow => [/google.com/, /yahoo.com/])` Thanks to [Bastien Vaucher](https://github.com/bastien) * Fixed `on_header` Curb callback behaviour in Curb adapter Thanks to [Joel Chippindale](https://github.com/mocoso) * Fixed aws-sdk compatibility with Ruby 2.0, by supporting `continue_timeout` accessor on Net::HTTP socket. Thanks to [Lin Jen-Shin](https://github.com/godfat) * Fixed WebMock::Server to not give "log writing failed. can't be called from trap context" warning with Ruby 2.0 Thanks to [Murahashi Sanemat Kenichi](https://github.com/sanemat) * Added support for EM-HTTP-Request streaming data off disk feature. Thanks to [Lin Jen-Shin](https://github.com/godfat) * Added compatibility with Minitest 5 Thanks to [Tim Kurvers](https://github.com/timkurvers) * Excon >= 0.22 compatibility. * README has nice sytnax hightlighting and fixed code styling! Thanks to [Ilya Vassilevsky](https://github.com/vassilevsky) * Compatibility with Rails 4 `rack.session.options` Thanks to [gotwalt](https://github.com/gotwalt) ## 1.11.0 * Excon >= 0.17 support. Thanks to [Nathan Sutton](https://github.com/nate) for reporting this issue and to [Wesley Beary](https://github.com/geemus) and [Myron Marston](https://github.com/myronmarston) for help. ## 1.10.2 * '+' in request path is treated as plus, but in query params always as a space. ## 1.10.1 * '+' in request body is still treated as a space. This fixes a bug introduced in previous version. Thanks to [Erik Michaels-Ober](https://github.com/sferik) for reporting this problem. * Fixed issue: response body declared as Proc was not evaluated again on subsequent requests. Thanks to [Rick Fletcher](https://github.com/rfletcher) for reporting this issue. ## 1.10.0 * '+' in query params is not treated as space anymore and is encoded as %2B Thanks to [goblin](https://github.com/goblin) for reporting this issue. * added `remove_request_stub` method to the api to allow removing unused stubs i.e. stub_get = stub_request(:get, "www.example.com") remove_request_stub(stub_get) * `assert_requested` and `assert_not_requested` raise an error if a stub object is provided together with a block. ## 1.9.3 * Fixed issue with unavailable constant Mutex in Ruby < 1.9 Thanks to [Lucas Dohmen](https://github.com/moonglum) for reporting this issue. ## 1.9.2 * Added support for Excon's :response_block parameter Thanks to [Myron Marston](https://github.com/myronmarston) for reporting this issue. ## 1.9.1 * Fix 'rack.errors' not being set for Rack apps Thanks to [Alex Grant](https://github.com/grantovich) * Added support for minitest assertions count Thanks to [Mokevnin Kirill](https://github.com/mokevnin) * Fixed issues with registering http requests in multi-threaded environments Thanks to [Tom Beauvais](https://github.com/tbeauvais) * Bumped Crack version to >=0.3.2 Thanks to [Jake Benilov](https://github.com/benilovj) * Fixed issues in Typhoeus 0.6. Defaulted method to GET when no method specified. Thanks to [Hans Hasselberg](https://github.com/i0rek) * Add license information to the gemspec Thanks to [Jordi Massaguer Pla](https://github.com/jordimassaguerpla) and [Murahashi Sanemat Kenichi](https://github.com/sanemat) * Added support for :expects option in Excon adapter Thanks to [Evgeniy Dolzhenko](https://github.com/dolzenko) * Fixed Faye compatibility by treating StringIO in Net::HTTP adapter properly Thanks to [Pavel Forkert](https://github.com/fxposter) * Updated VCR link Thanks to [Rex Feng](https://github.com/xta) ## 1.9.0 * Added support for Typhoeus >= 0.5.0 and removed support for Typhoeus < 0.5.0. Thanks to [Hans Hasselberg](https://github.com/i0rek) ## 1.8.11 * Fix excon adapter to handle `:body => some_file_object` Thanks to [Myron Marston](https://github.com/myronmarston) ## 1.8.10 * em-http-request fix. After request callbacks are correctly invoked for 3xx responses, when :redirects option is set. Thanks to [Myron Marston](https://github.com/myronmarston) for reporting that issue. * Fixed compatibility with Net::HTTP::DigestAuth Thanks to [Jonathan Hyman](https://github.com/jonhyman) for reporting that issue. * Fixed problem in em-http-request 0.x appending the query to the client URI twice. Thanks to [Paweł Pierzchała](https://github.com/wrozka) ## 1.8.9 * Fixed problem with caching nil responses when the same HTTPClient instance is used. Thanks to [Myron Marston](https://github.com/myronmarston) * Added support for Addressable >= 2.3.0. Addressable 2.3.0 removed support for multiple query value notations and broke backwards compatibility. https://github.com/sporkmonger/addressable/commit/f51e290b5f68a98293327a7da84eb9e2d5f21c62 https://github.com/sporkmonger/addressable/issues/77 ## 1.8.8 * Fixed Net::HTTP adapter so that it returns `nil` for an empty body response. Thanks to [Myron Marston](https://github.com/myronmarston) * Gemspec defines compatibility with Addressable ~> 2.2.8, not >= 2.3.0 * Specs compatibility with Typhoeus 0.4.0 Thanks to [Hans Hasselberg](https://github.com/i0rek) * Handling content types that specify a charset Thanks to [Kevin Glowacz](https://github.com/kjg) * Fixed em-http-request adapter to correctly fetch authorization header from a request Thanks to [Julien Boyer](https://github.com/chatgris) * Fixing travis-ci image to report master's status Thanks to [Ryan Schlesinger](https://github.com/ryansch) * Fixed problem with em-http-request callback triggering if there were other EM::Deferred callbacks registered Thanks to [Jon Leighton](https://github.com/jonleighton) * Fixed problem with em-http-request appending the query to the URI a second time, and the parameters are repeated. Thanks to [Jon Leighton](https://github.com/jonleighton) ## 1.8.7 * Compatibility with RSpec >= 2.10 Thanks to [erwanlr](https://github.com/erwanlr) for reporting this issue. * Add missing required rack environment variable SCRIPT_NAME Thanks to [Eric Oestrich](https://github.com/oestrich) * Fixed warnings due to @query_params not being initialized Thanks to [Ben Bleything](https://github.com/bleything) ## 1.8.6 * Pass through SERVER_PORT when stubbing to rack Thanks to [Eric Oestrich](https://github.com/oestrich) * Fixed problem with missing parenthesis in `WebMock#net_connect_allowed?` conditions. Thanks to [aindustries](https://github.com/aindustries) ## 1.8.5 * WebMock::RackResponse supports basic auth Thanks to [jugyo](https://github.com/jugyo) ## 1.8.4 * Warning message is printed when an unsupported version of a http library is loaded. Thanks to [Alexander Staubo](https://github.com/alexstaubo) for reporting the problem and to [Myron Marston](https://github.com/myronmarston) for a help with solution. ## 1.8.3 * Fixed compatibility with latest em-http-request Thanks to [Paul Cortens](https://github.com/thoughtless) ## 1.8.2 * Prevent Webmock `hash_including` from overriding RSpec version 1 `hash_including` method. Thanks to [Joe Karayusuf](https://github.com/karayusuf) * Ensured WebMock handles RSpec 1 `hash_including` matcher for matching query params and body. ## 1.8.1 * Ensured WebMock doesn't interfere with `em-synchrony`, when `em-synchrony/em-http` is not included. Thanks to [Nick Recobra](https://github.com/oruen) * Improved README Thanks to [Jordan Elver](https://github.com/jordelver) ## 1.8.0 * Matching request body against partial hash. stub_http_request(:post, "www.example.com"). with(:body => hash_including({:data => {:a => '1', :b => 'five'}})) RestClient.post('www.example.com', "data[a]=1&data[b]=five&x=1", :content_type => 'application/x-www-form-urlencoded') # ===> Success request(:post, "www.example.com"). with(:body => hash_including({:data => {:a => '1', :b => 'five'}}), :headers => 'Content-Type' => 'application/json').should have_been_made # ===> Success Thanks to [Marnen Laibow-Koser](https://github.com/marnen) for help with this solution * Matching request query params against partial hash. stub_http_request(:get, "www.example.com").with(:query => hash_including({"a" => ["b", "c"]})) RestClient.get("http://www.example.com/?a[]=b&a[]=c&x=1") # ===> Success request(:get, "www.example.com"). with(:query => hash_including({"a" => ["b", "c"]})).should have_been_made # ===> Success * Added support for Excon. Thanks to [Dimitrij Denissenko](https://github.com/dim) * Added support for setting expectations on the request stub with `assert_requested` stub_get = stub_request(:get, "www.example.com") stub_post = stub_request(:post, "www.example.com") Net::HTTP.get('www.example.com', '/') assert_requested(stub_get) assert_not_requested(stub_post) Thanks to [Nicolas Fouché](https://github.com/nfo) * `WebMock.disable_net_connect!` accepts `RegExp` as `:allow` parameter Thanks to [Frank Schumacher](https://github.com/thenoseman) * Ensure multiple values for the same header can be recorded and played back Thanks to [Myron Marston](https://github.com/myronmarston) * Updated dependency on Addressable to version >= 2.2.7 to handle nested hash query values. I.e. `?one[two][three][]=four&one[two][three][]=five` * Fixed compatibility with Curb >= 0.7.16 This breaks compatibility with Curb < 0.7.16 * Fix #to_rack to handle non-array response bodies. Thanks to [Tammer Saleh](https://github.com/tsaleh) * Added `read_timeout` accessor to StubSocket which fixes compatibility with aws-sdk Thanks to [Lin Jen-Shin](https://github.com/godfat) * Fix warning "instance variable @query_params not initialized" Thanks to [Joe Van Dyk](https://github.com/joevandyk) * Using bytesize of message instead of its length for content-length header in em-http-request adapter. This fixes a problem with messages getting truncated in Ruby >= 1.9 Thanks to [Mark Abramov](https://github.com/markiz) * Fixed problem with body params being matched even if params were different. Thanks to [Evgeniy Dolzhenko](https://github.com/dolzenko) for reporting this issue. ## 1.7.10 * Yanked 1.7.9 and rebuilt gem on 1.8.7 to deal with syck/psych incompatibilties in gemspec. ## 1.7.9 * Fixed support for native Typhoeus timeouts. Thanks to [Albert Llop](https://github.com/mrsimo) * Fixed problem with WebMock and RSpec compatibility on TeamCity servers. See [this article](http://www.coding4streetcred.com/blog/post/Issue-RubyMine-31-Webmock-162-and-%E2%80%9CSpecconfigure%E2%80%9D-curse.aspx) for more details. Thanks to [Christopher Pickslay](https://github.com/chrispix) from [Two Bit Labs](https://github.com/twobitlabs) ## 1.7.8 * Fix each adapter so that it calls a `stub.with` block only once per request. Previously, the block would be called two or three times per request [Myron Marston](https://github.com/myronmarston). ## 1.7.7 - RuPy 2011 release * Passing response object to a block passed to `HTTPClient#do_get_block`. This fixes `HTTPClient.get_content` failures. [issue 130](https://github.com/bblimke/webmock/pull/130) Thanks to [Chris McGrath](https://github.com/chrismcg) * Cleaned up ruby warnings when running WebMock code with `-w`. Thanks to [Stephen Celis](https://github.com/stephencelis) * Curb adapter now correctly calls on_failure for 4xx response codes. Thanks to [Eugene Pimenov](https://github.com/libc) ## 1.7.6 * Support for the HTTPClient's request_filter feature Thanks to [Roman Shterenzon](https://github.com/romanbsd) ## 1.7.5 * Added support for Patron 0.4.15. This change is not backward compatible so please upgrade Patron to version >= 0.4.15 if you want to use it with WebMock. Thanks to [Andreas Garnæs](https://github.com/andreas) ## 1.7.4 * Added support for matching EM-HTTP-Request requests with body declared as a Hash Thanks to [David Yeu](https://github.com/daveyeu) ## 1.7.3 * Added `Get`, `Post`, `Delete`, `Put`, `Head`, `Option` constants to replaced `Net::HTTP` to make it possible to marshal objects with these constants assigned to properties. This fixed problem with `tvdb_party` gem which serializes HTTParty responses. Thanks to [Klaus Hartl](https://github.com/carhartl) for reporting this issue. ## 1.7.2 * Redefined `const_get` and `constants` methods on the replaced `Net::HTTP` to return same values as original `Net::HTTP` ## 1.7.1 * Redefined `const_defined?` on the replaced `Net::HTTP` so that it returns true if constant is defined on the original `Net::HTTP`. This fixes problems with `"Net::HTTP::Get".constantize`. Thanks to [Cássio Marques](https://github.com/cassiomarques) for reporting the issue and to [Myron Marston](https://github.com/myronmarston) for help with the solution. ## 1.7.0 * Fixed Net::HTTP adapter to not break normal Net::HTTP behaviour when network connections are allowed. This fixes **selenium-webdriver compatibility**!!! * Added support for EM-HTTP-Request 1.0.x and EM-Synchrony. Thanks to [Steve Hull](https://github.com/sdhull) * Added support for setting expectations to on a stub itself i.e. stub = stub_request(:get, "www.example.com") # ... make requests ... stub.should have_been_requested Thanks to [Aidan Feldman](https://github.com/afeld) * Minitest support! Thanks to [Peter Higgins](https://github.com/phiggins) * Added support for Typhoeus::Hydra * Added support for `Curb::Easy#http_post` and `Curb::Easy#http_post` with multiple arguments. Thanks to [Salvador Fuentes Jr](https://github.com/fuentesjr) and [Alex Rothenberg](https://github.com/alexrothenberg) * Rack support. Requests can be stubbed to respond with a Rack app i.e. class MyRackApp def self.call(env) [200, {}, ["Hello"]] end end stub_request(:get, "www.example.com").to_rack(MyRackApp) RestClient.get("www.example.com") # ===> "Hello" Thanks to [Jay Adkisson](https://github.com/jayferd) * Added support for selective disabling and enabling of http lib adapters WebMock.disable! #disable WebMock (all adapters) WebMock.disable!(:except => [:net_http]) #disable WebMock for all libs except Net::HTTP WebMock.enable! #enable WebMock (all adapters) WebMock.enable!(:except => [:patron]) #enable WebMock for all libs except Patron * The error message on an unstubbed request shows a code snippet with body as a hash when it was in url encoded form. > RestClient.post('www.example.com', "data[a]=1&data[b]=2", :content_type => 'application/x-www-form-urlencoded') WebMock::NetConnectNotAllowedError: Real HTTP connections are disabled.... You can stub this request with the following snippet: stub_request(:post, "http://www.example.com/"). with(:body => {"data"=>{"a"=>"1", "b"=>"2"}}, :headers => { 'Content-Type'=>'application/x-www-form-urlencoded' }). to_return(:status => 200, :body => "", :headers => {}) Thanks to [Alex Rothenberg](https://github.com/alexrothenberg) * The error message on an unstubbed request shows currently registered request stubs. > stub_request(:get, "www.example.net") > stub_request(:get, "www.example.org") > RestClient.get("www.example.com") WebMock::NetConnectNotAllowedError: Real HTTP connections are disabled.... You can stub this request with the following snippet: stub_request(:get, "http://www.example.com/"). to_return(:status => 200, :body => "", :headers => {}) registered request stubs: stub_request(:get, "http://www.example.net/") stub_request(:get, "http://www.example.org/") Thanks to [Lin Jen-Shin](https://github.com/godfat) for suggesting this feature. * Fixed problem with matching requests with json body, when json strings have date format. Thanks to [Joakim Ekberg](https://github.com/kalasjocke) for reporting this issue. * WebMock now attempts to require each http library before monkey patching it. This is to avoid problem when http library is required after WebMock is required. Thanks to [Myron Marston](https://github.com/myronmarston) for suggesting this change. * External requests can be disabled while allowing selected ports on selected hosts WebMock.disable_net_connect!(:allow => "www.example.com:8080") RestClient.get("www.example.com:80") # ===> Failure RestClient.get("www.example.com:8080") # ===> Allowed. Thanks to [Zach Dennis](https://github.com/zdennis) * Fixed syntax error in README examples, showing the ways of setting request expectations. Thanks to [Nikita Fedyashev](https://github.com/nfedyashev) **Many thanks to WebMock co-maintainer [James Conroy-Finn](https://github.com/jcf) who did a great job maintaining WebMock on his own for the last couple of months.** ## 1.6.4 This is a quick slip release to regenerate the gemspec. Apparently jeweler inserts dependencies twice if you use the `gemspec` method in your Gemfile and declare gem dependencies in your gemspec. https://github.com/technicalpickles/jeweler/issues/154 josevalim: > This just bit me. I just released a gem with the wrong dependencies > because I have updated jeweler. This should have been opt-in, > otherwise a bunch of people using jeweler are going to release gems > with the wrong dependencies because you are automatically importing > from the Gemfile. ## 1.6.3 * Update the dependency on addressable to get around an issue in v2.2.5. Thanks to [Peter Higgins](https://github.com/phiggins). * Add support for matching parameter values using a regular expression as well as a string. Thanks to [Oleg M Prozorov](https://github.com/oleg). * Fix integration with httpclient as the internal API has changed. Thanks to [Frank Prößdorf](https://github.com/endor). * Ensure Curl::Easy#content_type is always set. Thanks to [Peter Higgins](https://github.com/phiggins). * Fix bug with em-http-request adapter stubbing responses that have a chunked transfer encoding. Thanks to [Myron Marston](https://github.com/myronmarston). * Fix a load of spec failures with Patron, httpclient, and specs that depended on the behaviour of example.com. Thanks to [Alex Grigorovich](https://github.com/grig). ## 1.6.2 * Em-http-request adapter sets `last_effective_url` property. Thanks to [Sam Stokes](https://github.com/samstokes). * Curb adapter supports `Curb::Easy#http_post` and `Curb::Easy#http_put` without arguments (by setting `post_body` or `put_data` beforehand). Thanks to [Eugene Bolshakov](https://github.com/eugenebolshakov) ## 1.6.1 * Fixed issue with `webmock/rspec` which didn't load correctly if `rspec/core` was already required but `rspec/expectations` not. ## 1.6.0 * Simplified integration with Test::Unit, RSpec and Cucumber. Now only a single file has to be required i.e. require 'webmock/test_unit' require 'webmock/rspec' require 'webmock/cucumber' * The error message on unstubbed request now contains code snippet which can be used to stub this request. Thanks to Martyn Loughran for suggesting this feature. * The expectation failure message now contains a list of made requests. Thanks to Martyn Loughran for suggesting this feature. * Added `WebMock.print_executed_requests` method which can be useful to find out what requests were made until a given point. * em-http-request adapter is now activated by replacing EventMachine::HttpRequest constant, instead of monkeypatching the original class. This technique is borrowed from em-http-request native mocking module. It allows switching WebMock adapter on an off, and using it interchangeably with em-http-request native mocking i.e: EventMachine::WebMockHttpRequest.activate! EventMachine::WebMockHttpRequest.deactivate! Thanks to Martyn Loughran for suggesting this feature. * `WebMock.reset_webmock` is deprecated in favour of new `WebMock.reset!` * Fixed integration with Cucumber. Previously documented example didn't work with new versions of Cucumber. * Fixed stubbing requests with body declared as a hash. Thanks to Erik Michaels-Ober for reporting the issue. * Fixed issue with em-http-request adapter which didn't work when :query option value was passed as a string, not a hash. Thanks to Chee Yeo for reporting the issue. * Fixed problem with assert_requested which didn't work if used outside rspec or test/unit * Removed dependency on json gem ## 1.5.0 * Support for dynamically evaluated raw responses recorded with `curl -is`:flat
, :dot
, or
# :subscript
. The :dot
notation is not
# supported for assignment. Default value is :subscript
.
#
# @return [Hash, Array] The query string parsed as a Hash or Array object.
#
# @example
# WebMock::Util::QueryMapper.query_to_values("?one=1&two=2&three=3")
# #=> {"one" => "1", "two" => "2", "three" => "3"}
# WebMock::Util::QueryMapper("?one[two][three]=four").query_values
# #=> {"one" => {"two" => {"three" => "four"}}}
# WebMock::Util::QueryMapper.query_to_values("?one.two.three=four",
# :notation => :dot
# )
# #=> {"one" => {"two" => {"three" => "four"}}}
# WebMock::Util::QueryMapper.query_to_values("?one[two][three]=four",
# :notation => :flat
# )
# #=> {"one[two][three]" => "four"}
# WebMock::Util::QueryMapper.query_to_values("?one.two.three=four",
# :notation => :flat
# )
# #=> {"one.two.three" => "four"}
# WebMock::Util::QueryMapper(
# "?one[two][three][]=four&one[two][three][]=five"
# )
# #=> {"one" => {"two" => {"three" => ["four", "five"]}}}
# WebMock::Util::QueryMapper.query_to_values(
# "?one=two&one=three").query_values(:notation => :flat_array)
# #=> [['one', 'two'], ['one', 'three']]
def query_to_values(query, options={})
return nil if query.nil?
query = query.dup.force_encoding('utf-8') if query.respond_to?(:force_encoding)
options[:notation] ||= :subscript
if ![:flat, :dot, :subscript, :flat_array].include?(options[:notation])
raise ArgumentError,
'Invalid notation. Must be one of: ' +
'[:flat, :dot, :subscript, :flat_array].'
end
empty_accumulator = :flat_array == options[:notation] ? [] : {}
query_array = collect_query_parts(query)
query_hash = collect_query_hash(query_array, empty_accumulator, options)
normalize_query_hash(query_hash, empty_accumulator, options)
end
def normalize_query_hash(query_hash, empty_accumulator, options)
query_hash.inject(empty_accumulator.dup) do |accumulator, (key, value)|
if options[:notation] == :flat_array
accumulator << [key, value]
else
accumulator[key] = value.kind_of?(Hash) ? dehash(value) : value
end
accumulator
end
end
def collect_query_parts(query)
query_parts = query.split('&').map do |pair|
pair.split('=', 2) if pair && !pair.empty?
end
query_parts.compact
end
def collect_query_hash(query_array, empty_accumulator, options)
query_array.compact.inject(empty_accumulator.dup) do |accumulator, (key, value)|
value = if value.nil?
nil
else
::Addressable::URI.unencode_component(value.tr('+', ' '))
end
key = Addressable::URI.unencode_component(key)
key = key.dup.force_encoding(Encoding::ASCII_8BIT) if key.respond_to?(:force_encoding)
self.__send__("fill_accumulator_for_#{options[:notation]}", accumulator, key, value)
accumulator
end
end
def fill_accumulator_for_flat(accumulator, key, value)
if accumulator[key]
raise ArgumentError, "Key was repeated: #{key.inspect}"
end
accumulator[key] = value
end
def fill_accumulator_for_flat_array(accumulator, key, value)
accumulator << [key, value]
end
def fill_accumulator_for_dot(accumulator, key, value)
array_value = false
subkeys = key.split(".")
current_hash = accumulator
subkeys[0..-2].each do |subkey|
current_hash[subkey] = {} unless current_hash[subkey]
current_hash = current_hash[subkey]
end
if array_value
if current_hash[subkeys.last] && !current_hash[subkeys.last].is_a?(Array)
current_hash[subkeys.last] = [current_hash[subkeys.last]]
end
current_hash[subkeys.last] = [] unless current_hash[subkeys.last]
current_hash[subkeys.last] << value
else
current_hash[subkeys.last] = value
end
end
def fill_accumulator_for_subscript(accumulator, key, value)
current_node = accumulator
subkeys = key.split(/(?=\[[^\[\]]+)/)
subkeys[0..-2].each do |subkey|
node = subkey =~ /\[\]\z/ ? [] : {}
subkey = subkey.gsub(/[\[\]]/, '')
if current_node.is_a? Array
container = current_node.find { |n| n.is_a?(Hash) && n.has_key?(subkey) }
if container
current_node = container[subkey]
else
current_node << {subkey => node}
current_node = node
end
else
current_node[subkey] = node unless current_node[subkey]
current_node = current_node[subkey]
end
end
last_key = subkeys.last
array_value = !!(last_key =~ /\[\]$/)
last_key = last_key.gsub(/[\[\]]/, '')
if current_node.is_a? Array
last_container = current_node.select { |n| n.is_a?(Hash) }.last
if last_container && !last_container.has_key?(last_key)
if array_value
last_container[last_key] ||= []
last_container[last_key] << value
else
last_container[last_key] = value
end
else
if array_value
current_node << {last_key => [value]}
else
current_node << {last_key => value}
end
end
else
if array_value
current_node[last_key] ||= []
current_node[last_key] << value unless value.nil?
else
current_node[last_key] = value
end
end
end
##
# Sets the query component for this URI from a Hash object.
# This method produces a query string using the :subscript notation.
# An empty Hash will result in a nil query.
#
# @param [Hash, #to_hash, Array] new_query_values The new query values.
def values_to_query(new_query_values, options = {})
options[:notation] ||= :subscript
return if new_query_values.nil?
unless new_query_values.is_a?(Array)
unless new_query_values.respond_to?(:to_hash)
raise TypeError,
"Can't convert #{new_query_values.class} into Hash."
end
new_query_values = new_query_values.to_hash
new_query_values = new_query_values.inject([]) do |object, (key, value)|
key = key.to_s if key.is_a?(::Symbol) || key.nil?
if value.is_a?(Array) && value.empty?
object << [key.to_s + '[]']
elsif value.is_a?(Array)
value.each { |v| object << [key.to_s + '[]', v] }
elsif value.is_a?(Hash)
value.each { |k, v| object << ["#{key.to_s}[#{k}]", v]}
else
object << [key.to_s, value]
end
object
end
# Useful default for OAuth and caching.
# Only to be used for non-Array inputs. Arrays should preserve order.
begin
new_query_values.sort! # may raise for non-comparable values
rescue NoMethodError, ArgumentError
# ignore
end
end
buffer = ''.dup
new_query_values.each do |parent, value|
encoded_parent = ::Addressable::URI.encode_component(
parent.dup, ::Addressable::URI::CharacterClasses::UNRESERVED
)
buffer << "#{to_query(encoded_parent, value, options)}&"
end
buffer.chop
end
def dehash(hash)
hash.each do |(key, value)|
if value.is_a?(::Hash)
hash[key] = self.dehash(value)
end
end
if hash != {} && hash.keys.all? { |key| key =~ /^\d+$/ }
hash.sort.inject([]) do |accu, (_, value)|
accu << value; accu
end
else
hash
end
end
##
# Joins and converts parent and value into a properly encoded and
# ordered URL query.
#
# @private
# @param [String] parent an URI encoded component.
# @param [Array, Hash, Symbol, #to_str] value
#
# @return [String] a properly escaped and ordered URL query.
# new_query_values have form [['key1', 'value1'], ['key2', 'value2']]
def to_query(parent, value, options = {})
options[:notation] ||= :subscript
case value
when ::Hash
value = value.map do |key, val|
[
::Addressable::URI.encode_component(key.to_s.dup, ::Addressable::URI::CharacterClasses::UNRESERVED),
val
]
end
value.sort!
buffer = ''.dup
value.each do |key, val|
new_parent = options[:notation] != :flat_array ? "#{parent}[#{key}]" : parent
buffer << "#{to_query(new_parent, val, options)}&"
end
buffer.chop
when ::Array
buffer = ''.dup
value.each_with_index do |val, i|
new_parent = options[:notation] != :flat_array ? "#{parent}[#{i}]" : parent
buffer << "#{to_query(new_parent, val, options)}&"
end
buffer.chop
when NilClass
parent
else
encoded_value = Addressable::URI.encode_component(
value.to_s.dup, Addressable::URI::CharacterClasses::UNRESERVED
)
"#{parent}=#{encoded_value}"
end
end
end
end
end
webmock-3.18.1/lib/webmock/util/headers.rb 0000644 0000041 0000041 00000003276 14333126774 020417 0 ustar www-data www-data require 'base64'
module WebMock
module Util
class Headers
def self.normalize_headers(headers)
return nil unless headers
array = headers.map { |name, value|
[name.to_s.split(/_|-/).map { |segment| segment.capitalize }.join("-"),
case value
when Regexp then value
when Array then (value.size == 1) ? value.first.to_s : value.map {|v| v.to_s}.sort
else value.to_s
end
]
}
Hash[*array.inject([]) {|r,x| r + x}]
end
def self.sorted_headers_string(headers)
headers = WebMock::Util::Headers.normalize_headers(headers)
str = '{'.dup
str << headers.map do |k,v|
v = case v
when Regexp then v.inspect
when Array then "["+v.map{|w| "'#{w.to_s}'"}.join(", ")+"]"
else "'#{v.to_s}'"
end
"'#{k}'=>#{v}"
end.sort.join(", ")
str << '}'
end
def self.pp_headers_string(headers)
headers = WebMock::Util::Headers.normalize_headers(headers)
seperator = "\n\t "
str = "{#{seperator} ".dup
str << headers.map do |k,v|
v = case v
when Regexp then v.inspect
when Array then "["+v.map{|w| "'#{w.to_s}'"}.join(", ")+"]"
else "'#{v.to_s}'"
end
"'#{k}'=>#{v}"
end.sort.join(",#{seperator} ")
str << "\n }"
end
def self.decode_userinfo_from_header(header)
header.sub(/^Basic /, "").unpack("m").first
end
def self.basic_auth_header(*credentials)
"Basic #{Base64.strict_encode64(credentials.join(':')).chomp}"
end
end
end
end
webmock-3.18.1/lib/webmock/util/hash_keys_stringifier.rb 0000644 0000041 0000041 00000001104 14333126774 023353 0 ustar www-data www-data module WebMock
module Util
class HashKeysStringifier
def self.stringify_keys!(arg, options = {})
case arg
when Array
arg.map { |elem|
options[:deep] ? stringify_keys!(elem, options) : elem
}
when Hash
Hash[
*arg.map { |key, value|
k = key.is_a?(Symbol) ? key.to_s : key
v = (options[:deep] ? stringify_keys!(value, options) : value)
[k,v]
}.inject([]) {|r,x| r + x}]
else
arg
end
end
end
end
end
webmock-3.18.1/lib/webmock/util/hash_counter.rb 0000644 0000041 0000041 00000001372 14333126774 021461 0 ustar www-data www-data require 'thread'
module WebMock
module Util
class HashCounter
attr_accessor :hash
def initialize
self.hash = {}
@order = {}
@max = 0
@lock = ::Mutex.new
end
def put key, num=1
@lock.synchronize do
hash[key] = (hash[key] || 0) + num
@order[key] = @max = @max + 1
end
end
def get key
@lock.synchronize do
hash[key] || 0
end
end
def select(&block)
return unless block_given?
@lock.synchronize do
hash.select(&block)
end
end
def each(&block)
@order.to_a.sort_by { |a| a[1] }.each do |a|
yield(a[0], hash[a[0]])
end
end
end
end
end
webmock-3.18.1/lib/webmock/minitest.rb 0000644 0000041 0000041 00000001774 14333126774 017664 0 ustar www-data www-data begin
require 'minitest/test'
test_class = Minitest::Test
assertions = "assertions"
rescue LoadError
require "minitest/unit"
test_class = MiniTest::Unit::TestCase
assertions = "_assertions"
end
require 'webmock'
WebMock.enable!
test_class.class_eval do
include WebMock::API
alias_method :teardown_without_webmock, :teardown
def teardown_with_webmock
teardown_without_webmock
WebMock.reset!
end
alias_method :teardown, :teardown_with_webmock
[:assert_request_requested, :assert_request_not_requested].each do |name|
alias_method :"#{name}_without_assertions_count", name
define_method :"#{name}_with_assertions_count" do |*args|
self.send("#{assertions}=", self.send("#{assertions}") + 1)
send :"#{name}_without_assertions_count", *args
end
alias_method name, :"#{name}_with_assertions_count"
end
end
begin
error_class = MiniTest::Assertion
rescue NameError
error_class = Minitest::Assertion
end
WebMock::AssertionFailure.error_class = error_class
webmock-3.18.1/lib/webmock/api.rb 0000644 0000041 0000041 00000007306 14333126774 016576 0 ustar www-data www-data module WebMock
module API
extend self
def stub_request(method, uri)
WebMock::StubRegistry.instance.
register_request_stub(WebMock::RequestStub.new(method, uri))
end
alias_method :stub_http_request, :stub_request
def a_request(method, uri)
WebMock::RequestPattern.new(method, uri)
end
class << self
alias :request :a_request
end
def assert_requested(*args, &block)
if not args[0].is_a?(WebMock::RequestStub)
args = convert_uri_method_and_options_to_request_and_options(args[0], args[1], args[2], &block)
elsif block
raise ArgumentError, "assert_requested with a stub object, doesn't accept blocks"
end
assert_request_requested(*args)
end
def assert_not_requested(*args, &block)
if not args[0].is_a?(WebMock::RequestStub)
args = convert_uri_method_and_options_to_request_and_options(args[0], args[1], args[2], &block)
elsif block
raise ArgumentError, "assert_not_requested with a stub object, doesn't accept blocks"
end
assert_request_not_requested(*args)
end
alias refute_requested assert_not_requested
# Similar to RSpec::Mocks::ArgumentMatchers#hash_including()
#
# Matches a hash that includes the specified key(s) or key/value pairs.
# Ignores any additional keys.
#
# @example
#
# object.should_receive(:message).with(hash_including(:key => val))
# object.should_receive(:message).with(hash_including(:key))
# object.should_receive(:message).with(hash_including(:key, :key2 => val2))
def hash_including(*args)
if defined?(super)
super
else
WebMock::Matchers::HashIncludingMatcher.new(anythingize_lonely_keys(*args))
end
end
def hash_excluding(*args)
if defined?(super)
super
else
WebMock::Matchers::HashExcludingMatcher.new(anythingize_lonely_keys(*args))
end
end
def remove_request_stub(stub)
WebMock::StubRegistry.instance.remove_request_stub(stub)
end
def reset_executed_requests!
WebMock::RequestRegistry.instance.reset!
end
private
def convert_uri_method_and_options_to_request_and_options(method, uri, options, &block)
options ||= {}
options_for_pattern = options.dup
[:times, :at_least_times, :at_most_times].each { |key| options_for_pattern.delete(key) }
request = WebMock::RequestPattern.new(method, uri, options_for_pattern)
request = request.with(&block) if block
[request, options]
end
def assert_request_requested(request, options = {})
times = options.delete(:times)
at_least_times = options.delete(:at_least_times)
at_most_times = options.delete(:at_most_times)
times = 1 if times.nil? && at_least_times.nil? && at_most_times.nil?
verifier = WebMock::RequestExecutionVerifier.new(request, times, at_least_times, at_most_times)
WebMock::AssertionFailure.failure(verifier.failure_message) unless verifier.matches?
end
def assert_request_not_requested(request, options = {})
times = options.delete(:times)
at_least_times = options.delete(:at_least_times)
at_most_times = options.delete(:at_most_times)
verifier = WebMock::RequestExecutionVerifier.new(request, times, at_least_times, at_most_times)
WebMock::AssertionFailure.failure(verifier.failure_message_when_negated) unless verifier.does_not_match?
end
#this is a based on RSpec::Mocks::ArgumentMatchers#anythingize_lonely_keys
def anythingize_lonely_keys(*args)
hash = args.last.class == Hash ? args.delete_at(-1) : {}
args.each { | arg | hash[arg] = WebMock::Matchers::AnyArgMatcher.new(nil) }
hash
end
end
end
webmock-3.18.1/lib/webmock/request_registry.rb 0000644 0000041 0000041 00000001466 14333126774 021446 0 ustar www-data www-data module WebMock
class RequestRegistry
include Singleton
attr_accessor :requested_signatures
def initialize
reset!
end
def reset!
self.requested_signatures = Util::HashCounter.new
end
def times_executed(request_pattern)
self.requested_signatures.select do |request_signature|
request_pattern.matches?(request_signature)
end.inject(0) { |sum, (_, times_executed)| sum + times_executed }
end
def to_s
if requested_signatures.hash.empty?
"No requests were made."
else
text = "".dup
self.requested_signatures.each do |request_signature, times_executed|
text << "#{request_signature} was made #{times_executed} time#{times_executed == 1 ? '' : 's' }\n"
end
text
end
end
end
end
webmock-3.18.1/lib/webmock/rspec/ 0000755 0000041 0000041 00000000000 14333126774 016606 5 ustar www-data www-data webmock-3.18.1/lib/webmock/rspec/matchers.rb 0000644 0000041 0000041 00000001131 14333126774 020735 0 ustar www-data www-data require 'webmock'
require 'webmock/rspec/matchers/request_pattern_matcher'
require 'webmock/rspec/matchers/webmock_matcher'
module WebMock
module Matchers
def have_been_made
WebMock::RequestPatternMatcher.new
end
def have_been_requested
WebMock::RequestPatternMatcher.new
end
def have_not_been_made
WebMock::RequestPatternMatcher.new.times(0)
end
def have_requested(method, uri)
WebMock::WebMockMatcher.new(method, uri)
end
def have_not_requested(method, uri)
WebMock::WebMockMatcher.new(method, uri).times(0)
end
end
end
webmock-3.18.1/lib/webmock/rspec/matchers/ 0000755 0000041 0000041 00000000000 14333126774 020414 5 ustar www-data www-data webmock-3.18.1/lib/webmock/rspec/matchers/request_pattern_matcher.rb 0000644 0000041 0000041 00000003406 14333126774 025674 0 ustar www-data www-data module WebMock
class RequestPatternMatcher
def initialize
@request_execution_verifier = RequestExecutionVerifier.new
end
def once
@request_execution_verifier.expected_times_executed = 1
self
end
def twice
@request_execution_verifier.expected_times_executed = 2
self
end
def times(times)
@request_execution_verifier.expected_times_executed = times.to_i
self
end
def at_least_once
@request_execution_verifier.at_least_times_executed = 1
self
end
def at_least_twice
@request_execution_verifier.at_least_times_executed = 2
self
end
def at_least_times(times)
@request_execution_verifier.at_least_times_executed = times.to_i
self
end
def at_most_once
@request_execution_verifier.at_most_times_executed = 1
self
end
def at_most_twice
@request_execution_verifier.at_most_times_executed = 2
self
end
def at_most_times(times)
@request_execution_verifier.at_most_times_executed = times.to_i
self
end
def matches?(request_pattern)
@request_execution_verifier.request_pattern = request_pattern
@request_execution_verifier.matches?
end
def does_not_match?(request_pattern)
@request_execution_verifier.request_pattern = request_pattern
@request_execution_verifier.does_not_match?
end
def failure_message
@request_execution_verifier.failure_message
end
def failure_message_when_negated
@request_execution_verifier.failure_message_when_negated
end
def description
@request_execution_verifier.description
end
# RSpec 2 compatibility:
alias_method :negative_failure_message, :failure_message_when_negated
end
end
webmock-3.18.1/lib/webmock/rspec/matchers/webmock_matcher.rb 0000644 0000041 0000041 00000002776 14333126774 024107 0 ustar www-data www-data module WebMock
class WebMockMatcher
def initialize(method, uri)
@request_execution_verifier = RequestExecutionVerifier.new
@request_execution_verifier.request_pattern = RequestPattern.new(method, uri)
end
def once
@request_execution_verifier.expected_times_executed = 1
self
end
def twice
@request_execution_verifier.expected_times_executed = 2
self
end
def at_least_once
@request_execution_verifier.at_least_times_executed = 1
self
end
def at_least_twice
@request_execution_verifier.at_least_times_executed = 2
self
end
def at_least_times(times)
@request_execution_verifier.at_least_times_executed = times
self
end
def with(options = {}, &block)
@request_execution_verifier.request_pattern.with(options, &block)
self
end
def times(times)
@request_execution_verifier.expected_times_executed = times.to_i
self
end
def matches?(webmock)
@request_execution_verifier.matches?
end
def does_not_match?(webmock)
@request_execution_verifier.does_not_match?
end
def failure_message
@request_execution_verifier.failure_message
end
def failure_message_when_negated
@request_execution_verifier.failure_message_when_negated
end
def description
@request_execution_verifier.description
end
# RSpec 2 compatibility:
alias_method :negative_failure_message, :failure_message_when_negated
end
end
webmock-3.18.1/lib/webmock/callback_registry.rb 0000644 0000041 0000041 00000001457 14333126774 021512 0 ustar www-data www-data module WebMock
class CallbackRegistry
@@callbacks = []
def self.add_callback(options, block)
@@callbacks << {options: options, block: block}
end
def self.callbacks
@@callbacks
end
def self.invoke_callbacks(options, request_signature, response)
return if @@callbacks.empty?
CallbackRegistry.callbacks.each do |callback|
except = callback[:options][:except]
real_only = callback[:options][:real_requests_only]
unless except && except.include?(options[:lib])
if !real_only || options[:real_request]
callback[:block].call(request_signature, response)
end
end
end
end
def self.reset
@@callbacks = []
end
def self.any_callbacks?
!@@callbacks.empty?
end
end
end
webmock-3.18.1/lib/webmock/request_body_diff.rb 0000644 0000041 0000041 00000002765 14333126774 021526 0 ustar www-data www-data require "hashdiff"
require "json"
module WebMock
class RequestBodyDiff
def initialize(request_signature, request_stub)
@request_signature = request_signature
@request_stub = request_stub
end
def body_diff
return {} unless request_signature_diffable? && request_stub_diffable?
Hashdiff.diff(request_signature_body_hash, request_stub_body_hash)
end
attr_reader :request_signature, :request_stub
private :request_signature, :request_stub
private
def request_signature_diffable?
request_signature.json_headers? && request_signature_parseable_json?
end
def request_stub_diffable?
request_stub_body.is_a?(Hash) || request_stub_parseable_json?
end
def request_signature_body_hash
JSON.parse(request_signature.body)
end
def request_stub_body_hash
return request_stub_body if request_stub_body.is_a?(Hash)
JSON.parse(request_stub_body)
end
def request_stub_body
request_stub.request_pattern &&
request_stub.request_pattern.body_pattern &&
request_stub.request_pattern.body_pattern.pattern
end
def request_signature_parseable_json?
parseable_json?(request_signature.body)
end
def request_stub_parseable_json?
parseable_json?(request_stub_body)
end
def parseable_json?(body_pattern)
return false unless body_pattern.is_a?(String)
JSON.parse(body_pattern)
true
rescue JSON::ParserError
false
end
end
end
webmock-3.18.1/lib/webmock/webmock.rb 0000644 0000041 0000041 00000011542 14333126774 017451 0 ustar www-data www-data module WebMock
def self.included(clazz)
WebMock::Deprecation.warning("include WebMock is deprecated. Please include WebMock::API instead")
if clazz.instance_methods.map(&:to_s).include?('request')
warn "WebMock#request was not included in #{clazz} to avoid name collision"
else
clazz.class_eval do
def request(method, uri)
WebMock::Deprecation.warning("WebMock#request is deprecated. Please use WebMock::API#a_request method instead")
WebMock.a_request(method, uri)
end
end
end
end
include WebMock::API
extend WebMock::API
class << self
alias :request :a_request
end
def self.version
VERSION
end
def self.disable!(options = {})
except = [options[:except]].flatten.compact
HttpLibAdapterRegistry.instance.each_adapter do |name, adapter|
adapter.enable!
adapter.disable! unless except.include?(name)
end
end
def self.enable!(options = {})
except = [options[:except]].flatten.compact
HttpLibAdapterRegistry.instance.each_adapter do |name, adapter|
adapter.disable!
adapter.enable! unless except.include?(name)
end
end
def self.allow_net_connect!(options = {})
Config.instance.allow_net_connect = true
Config.instance.net_http_connect_on_start = options[:net_http_connect_on_start]
end
def self.disable_net_connect!(options = {})
Config.instance.allow_net_connect = false
Config.instance.allow_localhost = options[:allow_localhost]
Config.instance.allow = options[:allow]
Config.instance.net_http_connect_on_start = options[:net_http_connect_on_start]
end
class << self
alias :enable_net_connect! :allow_net_connect!
alias :disallow_net_connect! :disable_net_connect!
end
def self.net_connect_allowed?(uri = nil)
return !!Config.instance.allow_net_connect if uri.nil?
if uri.is_a?(String)
uri = WebMock::Util::URI.normalize_uri(uri)
end
!!Config.instance.allow_net_connect ||
( Config.instance.allow_localhost && WebMock::Util::URI.is_uri_localhost?(uri) ||
Config.instance.allow && net_connect_explicit_allowed?(Config.instance.allow, uri) )
end
def self.net_http_connect_on_start?(uri)
allowed = Config.instance.net_http_connect_on_start || false
if [true, false].include?(allowed)
allowed
else
net_connect_explicit_allowed?(allowed, uri)
end
end
def self.net_connect_explicit_allowed?(allowed, uri=nil)
case allowed
when Array
allowed.any? { |allowed_item| net_connect_explicit_allowed?(allowed_item, uri) }
when Regexp
(uri.to_s =~ allowed) != nil ||
(uri.omit(:port).to_s =~ allowed) != nil && uri.port == uri.default_port
when String
allowed == uri.to_s ||
allowed == uri.host ||
allowed == "#{uri.host}:#{uri.port}" ||
allowed == "#{uri.scheme}://#{uri.host}:#{uri.port}" ||
allowed == "#{uri.scheme}://#{uri.host}" && uri.port == uri.default_port
else
if allowed.respond_to?(:call)
allowed.call(uri)
end
end
end
def self.show_body_diff!
Config.instance.show_body_diff = true
end
def self.hide_body_diff!
Config.instance.show_body_diff = false
end
def self.show_body_diff?
Config.instance.show_body_diff
end
def self.hide_stubbing_instructions!
Config.instance.show_stubbing_instructions = false
end
def self.show_stubbing_instructions!
Config.instance.show_stubbing_instructions = true
end
def self.show_stubbing_instructions?
Config.instance.show_stubbing_instructions
end
def self.reset!
WebMock::RequestRegistry.instance.reset!
WebMock::StubRegistry.instance.reset!
end
def self.reset_webmock
WebMock::Deprecation.warning("WebMock.reset_webmock is deprecated. Please use WebMock.reset! method instead")
reset!
end
def self.reset_callbacks
WebMock::CallbackRegistry.reset
end
def self.after_request(options={}, &block)
WebMock::CallbackRegistry.add_callback(options, block)
end
def self.registered_request?(request_signature)
WebMock::StubRegistry.instance.registered_request?(request_signature)
end
def self.print_executed_requests
puts WebMock::RequestExecutionVerifier.executed_requests_message
end
def self.globally_stub_request(order = :before_local_stubs, &block)
WebMock::StubRegistry.instance.register_global_stub(order, &block)
end
%w(
allow_net_connect!
disable_net_connect!
net_connect_allowed?
reset_webmock
reset_callbacks
after_request
registered_request?
).each do |method|
self.class_eval(%Q(
def #{method}(*args, &block)
WebMock::Deprecation.warning("WebMock##{method} instance method is deprecated. Please use WebMock.#{method} class method instead")
WebMock.#{method}(*args, &block)
end
))
end
end
webmock-3.18.1/lib/webmock/response.rb 0000644 0000041 0000041 00000010247 14333126774 017661 0 ustar www-data www-data require "pathname"
module WebMock
class ResponseFactory
def self.response_for(options)
if options.respond_to?(:call)
WebMock::DynamicResponse.new(options)
else
WebMock::Response.new(options)
end
end
end
class Response
def initialize(options = {})
case options
when IO, StringIO
self.options = read_raw_response(options)
when String
self.options = read_raw_response(StringIO.new(options))
else
self.options = options
end
end
def headers
@headers
end
def headers=(headers)
@headers = headers
if @headers && !@headers.is_a?(Proc)
@headers = Util::Headers.normalize_headers(@headers)
end
end
def body
@body || ''
end
def body=(body)
@body = body
assert_valid_body!
stringify_body!
end
def status
@status || [200, ""]
end
def status=(status)
@status = status.is_a?(Integer) ? [status, ""] : status
end
def exception
@exception
end
def exception=(exception)
@exception = case exception
when String then StandardError.new(exception)
when Class then exception.new('Exception from WebMock')
when Exception then exception
end
end
def raise_error_if_any
raise @exception if @exception
end
def should_timeout
@should_timeout == true
end
def options=(options)
options = WebMock::Util::HashKeysStringifier.stringify_keys!(options)
HashValidator.new(options).validate_keys('headers', 'status', 'body', 'exception', 'should_timeout')
self.headers = options['headers']
self.status = options['status']
self.body = options['body']
self.exception = options['exception']
@should_timeout = options['should_timeout']
end
def evaluate(request_signature)
self.body = @body.call(request_signature) if @body.is_a?(Proc)
self.headers = @headers.call(request_signature) if @headers.is_a?(Proc)
self.status = @status.call(request_signature) if @status.is_a?(Proc)
@should_timeout = @should_timeout.call(request_signature) if @should_timeout.is_a?(Proc)
@exception = @exception.call(request_signature) if @exception.is_a?(Proc)
self
end
def ==(other)
self.body == other.body &&
self.headers === other.headers &&
self.status == other.status &&
self.exception == other.exception &&
self.should_timeout == other.should_timeout
end
private
def stringify_body!
if @body.is_a?(IO) || @body.is_a?(Pathname)
io = @body
@body = io.read
io.close if io.respond_to?(:close)
end
end
def assert_valid_body!
valid_types = [Proc, IO, Pathname, String, Array]
return if @body.nil?
return if valid_types.any? { |c| @body.is_a?(c) }
if @body.class.is_a?(Hash)
raise InvalidBody, "must be one of: #{valid_types}, but you've used a #{@body.class}' instead." \
"\n What shall we encode it to? try calling .to_json .to_xml instead on the hash instead, or otherwise convert it to a string."
else
raise InvalidBody, "must be one of: #{valid_types}. '#{@body.class}' given"
end
end
def read_raw_response(io)
socket = ::Net::BufferedIO.new(io)
response = ::Net::HTTPResponse.read_new(socket)
transfer_encoding = response.delete('transfer-encoding') #chunks were already read by curl
response.reading_body(socket, true) {}
options = {}
options[:headers] = {}
response.each_header {|name, value| options[:headers][name] = value}
options[:headers]['transfer-encoding'] = transfer_encoding if transfer_encoding
options[:body] = response.read_body
options[:status] = [response.code.to_i, response.message]
options
ensure
socket.close
end
InvalidBody = Class.new(StandardError)
end
class DynamicResponse < Response
attr_accessor :responder
def initialize(responder)
@responder = responder
end
def evaluate(request_signature)
options = @responder.call(request_signature)
Response.new(options)
end
end
end
webmock-3.18.1/lib/webmock/request_pattern.rb 0000644 0000041 0000041 00000030755 14333126774 021256 0 ustar www-data www-data module WebMock
module RSpecMatcherDetector
def rSpecHashIncludingMatcher?(matcher)
matcher.class.name =~ /R?Spec::Mocks::ArgumentMatchers::HashIncludingMatcher/
end
def rSpecHashExcludingMatcher?(matcher)
matcher.class.name =~ /R?Spec::Mocks::ArgumentMatchers::HashExcludingMatcher/
end
end
class RequestPattern
attr_reader :method_pattern, :uri_pattern, :body_pattern, :headers_pattern
def initialize(method, uri, options = {})
@method_pattern = MethodPattern.new(method)
@uri_pattern = create_uri_pattern(uri)
@body_pattern = nil
@headers_pattern = nil
@with_block = nil
assign_options(options)
end
def with(options = {}, &block)
raise ArgumentError.new('#with method invoked with no arguments. Either options hash or block must be specified. Created a block with do..end? Try creating it with curly braces {} instead.') if options.empty? && !block_given?
assign_options(options)
@with_block = block
self
end
def matches?(request_signature)
content_type = request_signature.headers['Content-Type'] if request_signature.headers
content_type = content_type.split(';').first if content_type
@method_pattern.matches?(request_signature.method) &&
@uri_pattern.matches?(request_signature.uri) &&
(@body_pattern.nil? || @body_pattern.matches?(request_signature.body, content_type || "")) &&
(@headers_pattern.nil? || @headers_pattern.matches?(request_signature.headers)) &&
(@with_block.nil? || @with_block.call(request_signature))
end
def to_s
string = "#{@method_pattern.to_s.upcase}".dup
string << " #{@uri_pattern.to_s}"
string << " with body #{@body_pattern.to_s}" if @body_pattern
string << " with headers #{@headers_pattern.to_s}" if @headers_pattern
string << " with given block" if @with_block
string
end
private
def assign_options(options)
options = WebMock::Util::HashKeysStringifier.stringify_keys!(options, deep: true)
HashValidator.new(options).validate_keys('body', 'headers', 'query', 'basic_auth')
set_basic_auth_as_headers!(options)
@body_pattern = BodyPattern.new(options['body']) if options.has_key?('body')
@headers_pattern = HeadersPattern.new(options['headers']) if options.has_key?('headers')
@uri_pattern.add_query_params(options['query']) if options.has_key?('query')
end
def set_basic_auth_as_headers!(options)
if basic_auth = options.delete('basic_auth')
validate_basic_auth!(basic_auth)
options['headers'] ||= {}
options['headers']['Authorization'] = WebMock::Util::Headers.basic_auth_header(basic_auth[0],basic_auth[1])
end
end
def validate_basic_auth!(basic_auth)
if !basic_auth.is_a?(Array) || basic_auth.map{|e| e.is_a?(String)}.uniq != [true]
raise "The basic_auth option value should be an array which contains 2 strings: username and password"
end
end
def create_uri_pattern(uri)
if uri.is_a?(Regexp)
URIRegexpPattern.new(uri)
elsif uri.is_a?(Addressable::Template)
URIAddressablePattern.new(uri)
elsif uri.respond_to?(:call)
URICallablePattern.new(uri)
else
URIStringPattern.new(uri)
end
end
end
class MethodPattern
def initialize(pattern)
@pattern = pattern
end
def matches?(method)
@pattern == method || @pattern == :any
end
def to_s
@pattern.to_s
end
end
class URIPattern
include RSpecMatcherDetector
def initialize(pattern)
@pattern = if pattern.is_a?(Addressable::URI) \
|| pattern.is_a?(Addressable::Template)
pattern
elsif pattern.respond_to?(:call)
pattern
else
WebMock::Util::URI.normalize_uri(pattern)
end
@query_params = nil
end
def add_query_params(query_params)
@query_params = if query_params.is_a?(Hash)
query_params
elsif query_params.is_a?(WebMock::Matchers::HashIncludingMatcher) \
|| query_params.is_a?(WebMock::Matchers::HashExcludingMatcher)
query_params
elsif rSpecHashIncludingMatcher?(query_params)
WebMock::Matchers::HashIncludingMatcher.from_rspec_matcher(query_params)
elsif rSpecHashExcludingMatcher?(query_params)
WebMock::Matchers::HashExcludingMatcher.from_rspec_matcher(query_params)
else
WebMock::Util::QueryMapper.query_to_values(query_params, notation: Config.instance.query_values_notation)
end
end
def matches?(uri)
pattern_matches?(uri) && query_params_matches?(uri)
end
def to_s
str = pattern_inspect
str += " with query params #{@query_params.inspect}" if @query_params
str
end
private
def pattern_inspect
@pattern.inspect
end
def query_params_matches?(uri)
@query_params.nil? || @query_params == WebMock::Util::QueryMapper.query_to_values(uri.query, notation: Config.instance.query_values_notation)
end
end
class URICallablePattern < URIPattern
private
def pattern_matches?(uri)
@pattern.call(uri)
end
end
class URIRegexpPattern < URIPattern
private
def pattern_matches?(uri)
WebMock::Util::URI.variations_of_uri_as_strings(uri).any? { |u| u.match(@pattern) }
end
end
class URIAddressablePattern < URIPattern
def add_query_params(query_params)
@@add_query_params_warned ||= false
if not @@add_query_params_warned
@@add_query_params_warned = true
warn "WebMock warning: ignoring query params in RFC 6570 template and checking them with WebMock"
end
super(query_params)
end
private
def pattern_matches?(uri)
if @query_params.nil?
# Let Addressable check the whole URI
matches_with_variations?(uri)
else
# WebMock checks the query, Addressable checks everything else
matches_with_variations?(uri.omit(:query))
end
end
def pattern_inspect
@pattern.pattern.inspect
end
def matches_with_variations?(uri)
template =
begin
Addressable::Template.new(WebMock::Util::URI.heuristic_parse(@pattern.pattern))
rescue Addressable::URI::InvalidURIError
Addressable::Template.new(@pattern.pattern)
end
WebMock::Util::URI.variations_of_uri_as_strings(uri).any? { |u|
template_matches_uri?(template, u)
}
end
def template_matches_uri?(template, uri)
template.match(uri)
rescue Addressable::URI::InvalidURIError
false
end
end
class URIStringPattern < URIPattern
def add_query_params(query_params)
super
if @query_params.is_a?(Hash) || @query_params.is_a?(String)
query_hash = (WebMock::Util::QueryMapper.query_to_values(@pattern.query, notation: Config.instance.query_values_notation) || {}).merge(@query_params)
@pattern.query = WebMock::Util::QueryMapper.values_to_query(query_hash, notation: WebMock::Config.instance.query_values_notation)
@query_params = nil
end
end
private
def pattern_matches?(uri)
if @pattern.is_a?(Addressable::URI)
if @query_params
uri.omit(:query) === @pattern
else
uri === @pattern
end
else
false
end
end
def pattern_inspect
WebMock::Util::URI.strip_default_port_from_uri_string(@pattern.to_s)
end
end
class BodyPattern
include RSpecMatcherDetector
BODY_FORMATS = {
'text/xml' => :xml,
'application/xml' => :xml,
'application/json' => :json,
'text/json' => :json,
'application/javascript' => :json,
'text/javascript' => :json,
'text/html' => :html,
'application/x-yaml' => :yaml,
'text/yaml' => :yaml,
'text/plain' => :plain
}
attr_reader :pattern
def initialize(pattern)
@pattern = if pattern.is_a?(Hash)
normalize_hash(pattern)
elsif rSpecHashIncludingMatcher?(pattern)
WebMock::Matchers::HashIncludingMatcher.from_rspec_matcher(pattern)
else
pattern
end
end
def matches?(body, content_type = "")
assert_non_multipart_body(content_type)
if (@pattern).is_a?(Hash)
return true if @pattern.empty?
matching_body_hashes?(body_as_hash(body, content_type), @pattern, content_type)
elsif (@pattern).is_a?(Array)
matching_body_array?(body_as_hash(body, content_type), @pattern, content_type)
elsif (@pattern).is_a?(WebMock::Matchers::HashIncludingMatcher)
@pattern == body_as_hash(body, content_type)
else
empty_string?(@pattern) && empty_string?(body) ||
@pattern == body ||
@pattern === body
end
end
def to_s
@pattern.inspect
end
private
def body_as_hash(body, content_type)
case body_format(content_type)
when :json then
WebMock::Util::JSON.parse(body)
when :xml then
Crack::XML.parse(body)
else
WebMock::Util::QueryMapper.query_to_values(body, notation: Config.instance.query_values_notation)
end
end
def body_format(content_type)
normalized_content_type = content_type.sub(/\A(application\/)[a-zA-Z0-9.-]+\+(json|xml)\Z/,'\1\2')
BODY_FORMATS[normalized_content_type]
end
def assert_non_multipart_body(content_type)
if content_type =~ %r{^multipart/form-data}
raise ArgumentError.new("WebMock does not support matching body for multipart/form-data requests yet :(")
end
end
# Compare two hashes for equality
#
# For two hashes to match they must have the same length and all
# values must match when compared using `#===`.
#
# The following hashes are examples of matches:
#
# {a: /\d+/} and {a: '123'}
#
# {a: '123'} and {a: '123'}
#
# {a: {b: /\d+/}} and {a: {b: '123'}}
#
# {a: {b: 'wow'}} and {a: {b: 'wow'}}
#
# @param [Hash] query_parameters typically the result of parsing
# JSON, XML or URL encoded parameters.
#
# @param [Hash] pattern which contains keys with a string, hash or
# regular expression value to use for comparison.
#
# @return [Boolean] true if the paramaters match the comparison
# hash, false if not.
def matching_body_hashes?(query_parameters, pattern, content_type)
return false unless query_parameters.is_a?(Hash)
return false unless query_parameters.keys.sort == pattern.keys.sort
query_parameters.all? do |key, actual|
expected = pattern[key]
matching_values(actual, expected, content_type)
end
end
def matching_body_array?(query_parameters, pattern, content_type)
return false unless query_parameters.is_a?(Array)
return false unless query_parameters.length == pattern.length
query_parameters.each_with_index do |actual, index|
expected = pattern[index]
return false unless matching_values(actual, expected, content_type)
end
true
end
def matching_values(actual, expected, content_type)
return matching_body_hashes?(actual, expected, content_type) if actual.is_a?(Hash) && expected.is_a?(Hash)
return matching_body_array?(actual, expected, content_type) if actual.is_a?(Array) && expected.is_a?(Array)
expected = WebMock::Util::ValuesStringifier.stringify_values(expected) if url_encoded_body?(content_type)
expected === actual
end
def empty_string?(string)
string.nil? || string == ""
end
def normalize_hash(hash)
Hash[WebMock::Util::HashKeysStringifier.stringify_keys!(hash, deep: true).sort]
end
def url_encoded_body?(content_type)
content_type =~ %r{^application/x-www-form-urlencoded}
end
end
class HeadersPattern
def initialize(pattern)
@pattern = WebMock::Util::Headers.normalize_headers(pattern) || {}
end
def matches?(headers)
if empty_headers?(@pattern)
empty_headers?(headers)
else
return false if empty_headers?(headers)
@pattern.each do |key, value|
return false unless headers.has_key?(key) && value === headers[key]
end
true
end
end
def to_s
WebMock::Util::Headers.sorted_headers_string(@pattern)
end
def pp_to_s
WebMock::Util::Headers.pp_headers_string(@pattern)
end
private
def empty_headers?(headers)
headers.nil? || headers == {}
end
end
end
webmock-3.18.1/lib/webmock/cucumber.rb 0000644 0000041 0000041 00000000213 14333126774 017620 0 ustar www-data www-data require 'webmock'
require 'webmock/rspec/matchers'
WebMock.enable!
World(WebMock::API, WebMock::Matchers)
After do
WebMock.reset!
end
webmock-3.18.1/lib/webmock/http_lib_adapters/ 0000755 0000041 0000041 00000000000 14333126774 021162 5 ustar www-data www-data webmock-3.18.1/lib/webmock/http_lib_adapters/net_http.rb 0000644 0000041 0000041 00000021257 14333126774 023343 0 ustar www-data www-data require 'net/http'
require 'net/https'
require 'stringio'
require File.join(File.dirname(__FILE__), 'net_http_response')
module WebMock
module HttpLibAdapters
class NetHttpAdapter < HttpLibAdapter
adapter_for :net_http
OriginalNetHTTP = Net::HTTP unless const_defined?(:OriginalNetHTTP)
def self.enable!
Net.send(:remove_const, :HTTP)
Net.send(:remove_const, :HTTPSession)
Net.send(:const_set, :HTTP, @webMockNetHTTP)
Net.send(:const_set, :HTTPSession, @webMockNetHTTP)
end
def self.disable!
Net.send(:remove_const, :HTTP)
Net.send(:remove_const, :HTTPSession)
Net.send(:const_set, :HTTP, OriginalNetHTTP)
Net.send(:const_set, :HTTPSession, OriginalNetHTTP)
#copy all constants from @webMockNetHTTP to original Net::HTTP
#in case any constants were added to @webMockNetHTTP instead of Net::HTTP
#after WebMock was enabled.
#i.e Net::HTTP::DigestAuth
@webMockNetHTTP.constants.each do |constant|
if !OriginalNetHTTP.constants.map(&:to_s).include?(constant.to_s)
OriginalNetHTTP.send(:const_set, constant, @webMockNetHTTP.const_get(constant))
end
end
end
@webMockNetHTTP = Class.new(Net::HTTP) do
class << self
def socket_type
StubSocket
end
if Module.method(:const_defined?).arity == 1
def const_defined?(name)
super || self.superclass.const_defined?(name)
end
else
def const_defined?(name, inherit=true)
super || self.superclass.const_defined?(name, inherit)
end
end
if Module.method(:const_get).arity != 1
def const_get(name, inherit=true)
super
rescue NameError
self.superclass.const_get(name, inherit)
end
end
if Module.method(:constants).arity != 0
def constants(inherit=true)
(super + self.superclass.constants(inherit)).uniq
end
end
end
def request(request, body = nil, &block)
request_signature = WebMock::NetHTTPUtility.request_signature_from_request(self, request, body)
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
if webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
@socket = Net::HTTP.socket_type.new
WebMock::CallbackRegistry.invoke_callbacks(
{lib: :net_http}, request_signature, webmock_response)
build_net_http_response(webmock_response, &block)
elsif WebMock.net_connect_allowed?(request_signature.uri)
check_right_http_connection
after_request = lambda do |response|
if WebMock::CallbackRegistry.any_callbacks?
webmock_response = build_webmock_response(response)
WebMock::CallbackRegistry.invoke_callbacks(
{lib: :net_http, real_request: true}, request_signature, webmock_response)
end
response.extend Net::WebMockHTTPResponse
block.call response if block
response
end
super_with_after_request = lambda {
response = super(request, nil, &nil)
after_request.call(response)
}
if started?
ensure_actual_connection
super_with_after_request.call
else
start_with_connect {
super_with_after_request.call
}
end
else
raise WebMock::NetConnectNotAllowedError.new(request_signature)
end
end
def start_without_connect
raise IOError, 'HTTP session already opened' if @started
if block_given?
begin
@socket = Net::HTTP.socket_type.new
@started = true
return yield(self)
ensure
do_finish
end
end
@socket = Net::HTTP.socket_type.new
@started = true
self
end
def ensure_actual_connection
if @socket.is_a?(StubSocket)
@socket&.close
@socket = nil
do_start
end
end
alias_method :start_with_connect, :start
def start(&block)
uri = Addressable::URI.parse(WebMock::NetHTTPUtility.get_uri(self))
if WebMock.net_http_connect_on_start?(uri)
super(&block)
else
start_without_connect(&block)
end
end
def build_net_http_response(webmock_response, &block)
response = Net::HTTPResponse.send(:response_class, webmock_response.status[0].to_s).new("1.0", webmock_response.status[0].to_s, webmock_response.status[1])
body = webmock_response.body
body = nil if webmock_response.status[0].to_s == '204'
response.instance_variable_set(:@body, body)
webmock_response.headers.to_a.each do |name, values|
values = [values] unless values.is_a?(Array)
values.each do |value|
response.add_field(name, value)
end
end
response.instance_variable_set(:@read, true)
response.extend Net::WebMockHTTPResponse
if webmock_response.should_timeout
raise Net::OpenTimeout, "execution expired"
end
webmock_response.raise_error_if_any
yield response if block_given?
response
end
def build_webmock_response(net_http_response)
webmock_response = WebMock::Response.new
webmock_response.status = [
net_http_response.code.to_i,
net_http_response.message]
webmock_response.headers = net_http_response.to_hash
webmock_response.body = net_http_response.body
webmock_response
end
def check_right_http_connection
unless @@alredy_checked_for_right_http_connection ||= false
WebMock::NetHTTPUtility.puts_warning_for_right_http_if_needed
@@alredy_checked_for_right_http_connection = true
end
end
end
@webMockNetHTTP.version_1_2
[
[:Get, Net::HTTP::Get],
[:Post, Net::HTTP::Post],
[:Put, Net::HTTP::Put],
[:Delete, Net::HTTP::Delete],
[:Head, Net::HTTP::Head],
[:Options, Net::HTTP::Options]
].each do |c|
@webMockNetHTTP.const_set(c[0], c[1])
end
end
end
end
class StubSocket #:nodoc:
attr_accessor :read_timeout, :continue_timeout, :write_timeout
def initialize(*args)
@closed = false
end
def closed?
@closed
end
def close
@closed = true
nil
end
def readuntil(*args)
end
def io
@io ||= StubIO.new
end
class StubIO
def setsockopt(*args); end
def peer_cert; end
def peeraddr; ["AF_INET", 443, "127.0.0.1", "127.0.0.1"] end
def ssl_version; "TLSv1.3" end
def cipher; ["TLS_AES_128_GCM_SHA256", "TLSv1.3", 128, 128] end
end
end
module WebMock
module NetHTTPUtility
def self.request_signature_from_request(net_http, request, body = nil)
path = request.path
if path.respond_to?(:request_uri) #https://github.com/bblimke/webmock/issues/288
path = path.request_uri
end
path = WebMock::Util::URI.heuristic_parse(path).request_uri if path =~ /^http/
uri = get_uri(net_http, path)
method = request.method.downcase.to_sym
headers = Hash[*request.to_hash.map {|k,v| [k, v]}.inject([]) {|r,x| r + x}]
if request.body_stream
body = request.body_stream.read
request.body_stream = nil
end
if body != nil && body.respond_to?(:read)
request.set_body_internal body.read
else
request.set_body_internal body
end
WebMock::RequestSignature.new(method, uri, body: request.body, headers: headers)
end
def self.get_uri(net_http, path = nil)
protocol = net_http.use_ssl? ? "https" : "http"
hostname = net_http.address
hostname = "[#{hostname}]" if /\A\[.*\]\z/ !~ hostname && /:/ =~ hostname
"#{protocol}://#{hostname}:#{net_http.port}#{path}"
end
def self.check_right_http_connection
@was_right_http_connection_loaded = defined?(RightHttpConnection)
end
def self.puts_warning_for_right_http_if_needed
if !@was_right_http_connection_loaded && defined?(RightHttpConnection)
$stderr.puts "\nWarning: RightHttpConnection has to be required before WebMock is required !!!\n"
end
end
end
end
WebMock::NetHTTPUtility.check_right_http_connection
webmock-3.18.1/lib/webmock/http_lib_adapters/excon_adapter.rb 0000644 0000041 0000041 00000012203 14333126774 024321 0 ustar www-data www-data begin
require 'excon'
rescue LoadError
# excon not found
end
if defined?(Excon)
WebMock::VersionChecker.new('Excon', Excon::VERSION, '0.27.5').check_version!
module WebMock
module HttpLibAdapters
class ExconAdapter < HttpLibAdapter
PARAMS_TO_DELETE = [:expects, :idempotent,
:instrumentor_name, :instrumentor,
:response_block,
:__construction_args, :stack,
:connection, :response]
adapter_for :excon
instance_exec do
@original_excon_mock_default = nil
@stub = nil
end
def self.enable!
self.add_excon_stub
end
def self.disable!
self.remove_excon_stub
end
def self.add_excon_stub
if not @stub
@original_excon_mock_default = ::Excon.defaults[:mock]
::Excon.defaults[:mock] = true
@stub = ::Excon.stub({}) do |params|
self.handle_request(params)
end
end
end
def self.remove_excon_stub
::Excon.defaults[:mock] = @original_excon_mock_default
@original_excon_mock_default = nil
Excon.stubs.delete(@stub)
@stub = nil
end
def self.handle_request(params)
mock_request = self.build_request params.dup
WebMock::RequestRegistry.instance.requested_signatures.put(mock_request)
if mock_response = WebMock::StubRegistry.instance.response_for_request(mock_request)
self.perform_callbacks(mock_request, mock_response, real_request: false)
response = self.real_response(mock_response)
response
elsif WebMock.net_connect_allowed?(mock_request.uri)
conn = new_excon_connection(params)
real_response = conn.request(request_params_from(params.merge(mock: false)))
ExconAdapter.perform_callbacks(mock_request, ExconAdapter.mock_response(real_response), real_request: true)
real_response.data
else
raise WebMock::NetConnectNotAllowedError.new(mock_request)
end
end
def self.new_excon_connection(params)
# Ensure the connection is constructed with the exact same args
# that the orginal connection was constructed with.
args = params.fetch(:__construction_args)
::Excon::Connection.new(connection_params_from args.merge(mock: false))
end
def self.connection_params_from(hash)
hash = hash.dup
PARAMS_TO_DELETE.each { |key| hash.delete(key) }
hash
end
def self.request_params_from(hash)
hash = hash.dup
if defined?(Excon::VALID_REQUEST_KEYS)
hash.reject! {|key,_| !Excon::VALID_REQUEST_KEYS.include?(key) }
end
PARAMS_TO_DELETE.each { |key| hash.delete(key) }
hash
end
def self.to_query(hash)
string = "".dup
for key, values in hash
if values.nil?
string << key.to_s << '&'
else
for value in [*values]
string << key.to_s << '=' << CGI.escape(value.to_s) << '&'
end
end
end
string.chop! # remove trailing '&'
end
def self.build_request(params)
params = params.dup
params.delete(:user)
params.delete(:password)
method = (params.delete(:method) || :get).to_s.downcase.to_sym
params[:query] = to_query(params[:query]) if params[:query].is_a?(Hash)
uri = Addressable::URI.new(params).to_s
WebMock::RequestSignature.new method, uri, body: body_from(params), headers: params[:headers]
end
def self.body_from(params)
body = params[:body]
return body unless body.respond_to?(:read)
contents = body.read
body.rewind if body.respond_to?(:rewind)
contents
end
def self.real_response(mock)
raise Excon::Errors::Timeout if mock.should_timeout
mock.raise_error_if_any
{
body: mock.body,
status: mock.status[0].to_i,
reason_phrase: mock.status[1],
headers: mock.headers || {}
}
end
def self.mock_response(real)
mock = WebMock::Response.new
mock.status = [real.status, real.reason_phrase]
mock.headers = real.headers
mock.body = real.body.dup
mock
end
def self.perform_callbacks(request, response, options = {})
return unless WebMock::CallbackRegistry.any_callbacks?
WebMock::CallbackRegistry.invoke_callbacks(options.merge(lib: :excon), request, response)
end
end
end
end
Excon::Connection.class_eval do
def self.new(args = {})
args.delete(:__construction_args)
super(args).tap do |instance|
instance.data[:__construction_args] = args
end
end
end
# Suppresses Excon connection argument validation warning
Excon::VALID_CONNECTION_KEYS << :__construction_args
end
webmock-3.18.1/lib/webmock/http_lib_adapters/async_http_client_adapter.rb 0000644 0000041 0000041 00000015072 14333126774 026726 0 ustar www-data www-data begin
require 'async'
require 'async/http'
rescue LoadError
# async-http not found
end
if defined?(Async::HTTP)
module WebMock
module HttpLibAdapters
class AsyncHttpClientAdapter < HttpLibAdapter
adapter_for :async_http_client
OriginalAsyncHttpClient = Async::HTTP::Client unless const_defined?(:OriginalAsyncHttpClient)
class << self
def enable!
Async::HTTP.send(:remove_const, :Client)
Async::HTTP.send(:const_set, :Client, Async::HTTP::WebMockClientWrapper)
end
def disable!
Async::HTTP.send(:remove_const, :Client)
Async::HTTP.send(:const_set, :Client, OriginalAsyncHttpClient)
end
end
end
end
end
module Async
module HTTP
class WebMockClientWrapper < Client
def initialize(
endpoint,
protocol = endpoint.protocol,
scheme = endpoint.scheme,
authority = endpoint.authority,
**options
)
webmock_endpoint = WebMockEndpoint.new(scheme, authority, protocol)
@network_client = WebMockClient.new(endpoint, **options)
@webmock_client = WebMockClient.new(webmock_endpoint, **options)
@scheme = scheme
@authority = authority
end
def call(request)
request.scheme ||= self.scheme
request.authority ||= self.authority
request_signature = build_request_signature(request)
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
net_connect_allowed = WebMock.net_connect_allowed?(request_signature.uri)
real_request = false
if webmock_response
webmock_response.raise_error_if_any
raise Async::TimeoutError, 'WebMock timeout error' if webmock_response.should_timeout
WebMockApplication.add_webmock_response(request, webmock_response)
response = @webmock_client.call(request)
elsif net_connect_allowed
response = @network_client.call(request)
real_request = true
else
raise WebMock::NetConnectNotAllowedError.new(request_signature) unless webmock_response
end
if WebMock::CallbackRegistry.any_callbacks?
webmock_response ||= build_webmock_response(response)
WebMock::CallbackRegistry.invoke_callbacks(
{
lib: :async_http_client,
real_request: real_request
},
request_signature,
webmock_response
)
end
response
end
def close
@network_client.close
@webmock_client.close
end
private
def build_request_signature(request)
body = request.read
request.body = ::Protocol::HTTP::Body::Buffered.wrap(body)
WebMock::RequestSignature.new(
request.method.downcase.to_sym,
"#{request.scheme}://#{request.authority}#{request.path}",
headers: request.headers.to_h,
body: body
)
end
def build_webmock_response(response)
body = response.read
response.body = ::Protocol::HTTP::Body::Buffered.wrap(body)
webmock_response = WebMock::Response.new
webmock_response.status = [
response.status,
::Protocol::HTTP1::Reason::DESCRIPTIONS[response.status]
]
webmock_response.headers = build_webmock_response_headers(response)
webmock_response.body = body
webmock_response
end
def build_webmock_response_headers(response)
response.headers.each.each_with_object({}) do |(k, v), o|
o[k] ||= []
o[k] << v
end
end
end
class WebMockClient < Client
end
class WebMockEndpoint
def initialize(scheme, authority, protocol)
@scheme = scheme
@authority = authority
@protocol = protocol
end
attr :scheme, :authority, :protocol
def connect
server_socket, client_socket = create_connected_sockets
Async(transient: true) do
accept_socket(server_socket)
end
client_socket
end
def inspect
"\#<#{self.class}> #{scheme}://#{authority} protocol=#{protocol}"
end
private
def create_connected_sockets
pair = begin
Async::IO::Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM)
rescue Errno::EAFNOSUPPORT
Async::IO::Socket.pair(Socket::AF_INET, Socket::SOCK_STREAM)
end
pair.tap do |sockets|
sockets.each do |socket|
socket.instance_variable_set :@alpn_protocol, nil
socket.instance_eval do
def alpn_protocol
nil # means HTTP11 will be used for HTTPS
end
end
end
end
end
def accept_socket(socket)
server = Async::HTTP::Server.new(WebMockApplication, self)
server.accept(socket, socket.remote_address)
end
end
module WebMockApplication
WEBMOCK_REQUEST_ID_HEADER = 'x-webmock-request-id'.freeze
class << self
def call(request)
request.read
webmock_response = get_webmock_response(request)
build_response(webmock_response)
end
def add_webmock_response(request, webmock_response)
webmock_request_id = request.object_id.to_s
request.headers.add(WEBMOCK_REQUEST_ID_HEADER, webmock_request_id)
webmock_responses[webmock_request_id] = webmock_response
end
def get_webmock_response(request)
webmock_request_id = request.headers[WEBMOCK_REQUEST_ID_HEADER][0]
webmock_responses.fetch(webmock_request_id)
end
private
def webmock_responses
@webmock_responses ||= {}
end
def build_response(webmock_response)
headers = (webmock_response.headers || {}).each_with_object([]) do |(k, value), o|
Array(value).each do |v|
o.push [k, v]
end
end
::Protocol::HTTP::Response[
webmock_response.status[0],
headers,
webmock_response.body
]
end
end
end
end
end
end
webmock-3.18.1/lib/webmock/http_lib_adapters/curb_adapter.rb 0000644 0000041 0000041 00000023512 14333126774 024145 0 ustar www-data www-data begin
require 'curb'
rescue LoadError
# curb not found
end
if defined?(Curl)
WebMock::VersionChecker.new('Curb', Curl::CURB_VERSION, '0.7.16', '1.0.1', ['0.8.7']).check_version!
module WebMock
module HttpLibAdapters
class CurbAdapter < HttpLibAdapter
adapter_for :curb
OriginalCurlEasy = Curl::Easy unless const_defined?(:OriginalCurlEasy)
def self.enable!
Curl.send(:remove_const, :Easy)
Curl.send(:const_set, :Easy, Curl::WebMockCurlEasy)
end
def self.disable!
Curl.send(:remove_const, :Easy)
Curl.send(:const_set, :Easy, OriginalCurlEasy)
end
# Borrowed from Patron:
# http://github.com/toland/patron/blob/master/lib/patron/response.rb
def self.parse_header_string(header_string)
status, headers = nil, {}
header_string.split(/\r\n/).each do |header|
if header =~ %r|^HTTP/1.[01] \d\d\d (.*)|
status = $1
else
parts = header.split(':', 2)
unless parts.empty?
parts[1].strip! unless parts[1].nil?
if headers.has_key?(parts[0])
headers[parts[0]] = [headers[parts[0]]] unless headers[parts[0]].kind_of? Array
headers[parts[0]] << parts[1]
else
headers[parts[0]] = parts[1]
end
end
end
end
return status, headers
end
end
end
end
module Curl
class WebMockCurlEasy < Curl::Easy
def curb_or_webmock
request_signature = build_request_signature
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
if webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
build_curb_response(webmock_response)
WebMock::CallbackRegistry.invoke_callbacks(
{lib: :curb}, request_signature, webmock_response)
invoke_curb_callbacks
true
elsif WebMock.net_connect_allowed?(request_signature.uri)
res = yield
if WebMock::CallbackRegistry.any_callbacks?
webmock_response = build_webmock_response
WebMock::CallbackRegistry.invoke_callbacks(
{lib: :curb, real_request: true}, request_signature,
webmock_response)
end
res
else
raise WebMock::NetConnectNotAllowedError.new(request_signature)
end
end
def build_request_signature
method = @webmock_method.to_s.downcase.to_sym
uri = WebMock::Util::URI.heuristic_parse(self.url)
uri.path = uri.normalized_path.gsub("[^:]//","/")
headers = headers_as_hash(self.headers).merge(basic_auth_headers)
request_body = case method
when :post, :patch
self.post_body || @post_body
when :put
@put_data
else
nil
end
if defined?( @on_debug )
@on_debug.call("Trying 127.0.0.1...\r\n", 0)
@on_debug.call('Connected to ' + uri.hostname + "\r\n", 0)
@debug_method = method.upcase
@debug_path = uri.path
@debug_host = uri.hostname
http_request = ["#{@debug_method} #{@debug_path} HTTP/1.1"]
http_request << "Host: #{uri.hostname}"
headers.each do |name, value|
http_request << "#{name}: #{value}"
end
@on_debug.call(http_request.join("\r\n") + "\r\n\r\n", 2)
if request_body
@on_debug.call(request_body + "\r\n", 4)
@on_debug.call(
"upload completely sent off: #{request_body.bytesize}"\
" out of #{request_body.bytesize} bytes\r\n", 0
)
end
end
request_signature = WebMock::RequestSignature.new(
method,
uri.to_s,
body: request_body,
headers: headers
)
request_signature
end
def headers_as_hash(headers)
if headers.is_a?(Array)
headers.inject({}) {|hash, header|
name, value = header.split(":", 2).map(&:strip)
hash[name] = value
hash
}
else
headers
end
end
def basic_auth_headers
if self.username
{'Authorization' => WebMock::Util::Headers.basic_auth_header(self.username, self.password)}
else
{}
end
end
def build_curb_response(webmock_response)
raise Curl::Err::TimeoutError if webmock_response.should_timeout
webmock_response.raise_error_if_any
@body_str = webmock_response.body
@response_code = webmock_response.status[0]
@header_str = "HTTP/1.1 #{webmock_response.status[0]} #{webmock_response.status[1]}\r\n".dup
@on_debug.call(@header_str, 1) if defined?( @on_debug )
if webmock_response.headers
@header_str << webmock_response.headers.map do |k,v|
header = "#{k}: #{v.is_a?(Array) ? v.join(", ") : v}"
@on_debug.call(header + "\r\n", 1) if defined?( @on_debug )
header
end.join("\r\n")
@on_debug.call("\r\n", 1) if defined?( @on_debug )
location = webmock_response.headers['Location']
if self.follow_location? && location
@last_effective_url = location
webmock_follow_location(location)
end
@content_type = webmock_response.headers["Content-Type"]
@transfer_encoding = webmock_response.headers["Transfer-Encoding"]
end
@last_effective_url ||= self.url
end
def webmock_follow_location(location)
first_url = self.url
self.url = location
curb_or_webmock do
send( :http, {'method' => @webmock_method} )
end
self.url = first_url
end
def invoke_curb_callbacks
@on_progress.call(0.0,1.0,0.0,1.0) if defined?( @on_progress )
self.header_str.lines.each { |header_line| @on_header.call header_line } if defined?( @on_header )
if defined?( @on_body )
if chunked_response?
self.body_str.each do |chunk|
@on_body.call(chunk)
end
else
@on_body.call(self.body_str)
end
end
@on_complete.call(self) if defined?( @on_complete )
case response_code
when 200..299
@on_success.call(self) if defined?( @on_success )
when 400..499
@on_missing.call(self, self.response_code) if defined?( @on_missing )
when 500..599
@on_failure.call(self, self.response_code) if defined?( @on_failure )
end
end
def chunked_response?
defined?( @transfer_encoding ) && @transfer_encoding == 'chunked' && self.body_str.respond_to?(:each)
end
def build_webmock_response
status, headers =
WebMock::HttpLibAdapters::CurbAdapter.parse_header_string(self.header_str)
if defined?( @on_debug )
http_response = ["HTTP/1.0 #{@debug_method} #{@debug_path}"]
headers.each do |name, value|
http_response << "#{name}: #{value}"
end
http_response << self.body_str
@on_debug.call(http_response.join("\r\n") + "\r\n", 3)
@on_debug.call("Connection #0 to host #{@debug_host} left intact\r\n", 0)
end
webmock_response = WebMock::Response.new
webmock_response.status = [self.response_code, status]
webmock_response.body = self.body_str
webmock_response.headers = headers
webmock_response
end
###
### Mocks of Curl::Easy methods below here.
###
def http(method)
@webmock_method = method
super
end
%w[ get head delete ].each do |verb|
define_method "http_#{verb}" do
@webmock_method = verb
super()
end
end
def http_put data = nil
@webmock_method = :put
@put_data = data if data
super
end
alias put http_put
def http_post *data
@webmock_method = :post
@post_body = data.join('&') if data && !data.empty?
super
end
alias post http_post
def perform
@webmock_method ||= :get
curb_or_webmock { super }
ensure
reset_webmock_method
end
def put_data= data
@webmock_method = :put
@put_data = data
super
end
def post_body= data
@webmock_method = :post
super
end
def delete= value
@webmock_method = :delete if value
super
end
def head= value
@webmock_method = :head if value
super
end
def verbose=(verbose)
@verbose = verbose
end
def verbose?
@verbose ||= false
end
def body_str
@body_str ||= super
end
alias body body_str
def response_code
@response_code ||= super
end
def header_str
@header_str ||= super
end
alias head header_str
def last_effective_url
@last_effective_url ||= super
end
def content_type
@content_type ||= super
end
%w[ success failure missing header body complete progress debug ].each do |callback|
class_eval <<-METHOD, __FILE__, __LINE__
def on_#{callback} &block
@on_#{callback} = block
super
end
METHOD
end
def reset_webmock_method
@webmock_method = :get
end
def reset
instance_variable_set(:@body_str, nil)
instance_variable_set(:@content_type, nil)
instance_variable_set(:@header_str, nil)
instance_variable_set(:@last_effective_url, nil)
instance_variable_set(:@response_code, nil)
super
end
end
end
end
webmock-3.18.1/lib/webmock/http_lib_adapters/http_lib_adapter_registry.rb 0000644 0000041 0000041 00000000511 14333126774 026741 0 ustar www-data www-data module WebMock
class HttpLibAdapterRegistry
include Singleton
attr_accessor :http_lib_adapters
def initialize
@http_lib_adapters = {}
end
def register(lib, adapter)
@http_lib_adapters[lib] = adapter
end
def each_adapter(&block)
@http_lib_adapters.each(&block)
end
end
end webmock-3.18.1/lib/webmock/http_lib_adapters/manticore_adapter.rb 0000644 0000041 0000041 00000012227 14333126774 025174 0 ustar www-data www-data begin
require 'manticore'
rescue LoadError
# manticore not found
end
if defined?(Manticore)
module WebMock
module HttpLibAdapters
class ManticoreAdapter < HttpLibAdapter
adapter_for :manticore
OriginalManticoreClient = Manticore::Client
def self.enable!
Manticore.send(:remove_const, :Client)
Manticore.send(:const_set, :Client, WebMockManticoreClient)
Manticore.instance_variable_set(:@manticore_facade, WebMockManticoreClient.new)
end
def self.disable!
Manticore.send(:remove_const, :Client)
Manticore.send(:const_set, :Client, OriginalManticoreClient)
Manticore.instance_variable_set(:@manticore_facade, OriginalManticoreClient.new)
end
class StubbedTimeoutResponse < Manticore::StubbedResponse
def call
@handlers[:failure].call(Manticore::ConnectTimeout.new("Too slow (mocked timeout)"))
end
end
class WebMockManticoreClient < Manticore::Client
def request(klass, url, options={}, &block)
super(klass, WebMock::Util::URI.normalize_uri(url).to_s, format_options(options))
end
private
def format_options(options)
return options unless headers = options[:headers]
options.merge(headers: join_array_values(headers))
end
def join_array_values(headers)
headers.reduce({}) do |h, (k,v)|
v = v.join(', ') if v.is_a?(Array)
h.merge(k => v)
end
end
def response_object_for(request, context, &block)
request_signature = generate_webmock_request_signature(request, context)
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
if webmock_response = registered_response_for(request_signature)
webmock_response.raise_error_if_any
manticore_response = generate_manticore_response(webmock_response)
manticore_response.on_success do
WebMock::CallbackRegistry.invoke_callbacks({lib: :manticore, real_request: false}, request_signature, webmock_response)
end
elsif real_request_allowed?(request_signature.uri)
manticore_response = Manticore::Response.new(self, request, context, &block)
manticore_response.on_complete do |completed_response|
webmock_response = generate_webmock_response(completed_response)
WebMock::CallbackRegistry.invoke_callbacks({lib: :manticore, real_request: true}, request_signature, webmock_response)
end
else
raise WebMock::NetConnectNotAllowedError.new(request_signature)
end
manticore_response
end
def registered_response_for(request_signature)
WebMock::StubRegistry.instance.response_for_request(request_signature)
end
def real_request_allowed?(uri)
WebMock.net_connect_allowed?(uri)
end
def generate_webmock_request_signature(request, context)
method = request.method.downcase
uri = request.uri.to_s
body = read_body(request)
headers = split_array_values(request.headers)
if context.get_credentials_provider && credentials = context.get_credentials_provider.get_credentials(AuthScope::ANY)
headers['Authorization'] = WebMock::Util::Headers.basic_auth_header(credentials.get_user_name,credentials.get_password)
end
WebMock::RequestSignature.new(method, uri, {body: body, headers: headers})
end
def read_body(request)
if request.respond_to?(:entity) && !request.entity.nil?
Manticore::EntityConverter.new.read_entity(request.entity)
end
end
def split_array_values(headers = [])
headers.each_with_object({}) do |(k, v), h|
h[k] = case v
when /,/ then v.split(',').map(&:strip)
else v
end
end
end
def generate_manticore_response(webmock_response)
if webmock_response.should_timeout
StubbedTimeoutResponse.new
else
Manticore::StubbedResponse.stub(
code: webmock_response.status[0],
body: webmock_response.body,
headers: webmock_response.headers,
cookies: {}
)
end
end
def generate_webmock_response(manticore_response)
webmock_response = WebMock::Response.new
webmock_response.status = [manticore_response.code, manticore_response.message]
webmock_response.headers = manticore_response.headers
# The attempt to read the body could fail if manticore is used in a streaming mode
webmock_response.body = begin
manticore_response.body
rescue ::Manticore::StreamClosedException
nil
end
webmock_response
end
end
end
end
end
end
webmock-3.18.1/lib/webmock/http_lib_adapters/http_rb_adapter.rb 0000644 0000041 0000041 00000001504 14333126774 024651 0 ustar www-data www-data begin
require "http"
rescue LoadError
# HTTP gem not found
end
if defined?(HTTP) && defined?(HTTP::VERSION)
WebMock::VersionChecker.new("HTTP Gem", HTTP::VERSION, "0.6.0").check_version!
module WebMock
module HttpLibAdapters
class HttpRbAdapter < HttpLibAdapter
adapter_for :http_rb
class << self
def enable!
@enabled = true
end
def disable!
@enabled = false
end
def enabled?
@enabled
end
end
end
end
end
require "webmock/http_lib_adapters/http_rb/client"
require "webmock/http_lib_adapters/http_rb/request"
require "webmock/http_lib_adapters/http_rb/response"
require "webmock/http_lib_adapters/http_rb/streamer"
require "webmock/http_lib_adapters/http_rb/webmock"
end
webmock-3.18.1/lib/webmock/http_lib_adapters/em_http_request_adapter.rb 0000644 0000041 0000041 00000016147 14333126774 026430 0 ustar www-data www-data begin
require 'em-http-request'
rescue LoadError
# em-http-request not found
end
if defined?(EventMachine::HttpClient)
module WebMock
module HttpLibAdapters
class EmHttpRequestAdapter < HttpLibAdapter
adapter_for :em_http_request
OriginalHttpClient = EventMachine::HttpClient unless const_defined?(:OriginalHttpClient)
OriginalHttpConnection = EventMachine::HttpConnection unless const_defined?(:OriginalHttpConnection)
def self.enable!
EventMachine.send(:remove_const, :HttpConnection)
EventMachine.send(:const_set, :HttpConnection, EventMachine::WebMockHttpConnection)
EventMachine.send(:remove_const, :HttpClient)
EventMachine.send(:const_set, :HttpClient, EventMachine::WebMockHttpClient)
end
def self.disable!
EventMachine.send(:remove_const, :HttpConnection)
EventMachine.send(:const_set, :HttpConnection, OriginalHttpConnection)
EventMachine.send(:remove_const, :HttpClient)
EventMachine.send(:const_set, :HttpClient, OriginalHttpClient)
end
end
end
end
module EventMachine
if defined?(Synchrony) && HTTPMethods.instance_methods.include?(:aget)
# have to make the callbacks fire on the next tick in order
# to avoid the dreaded "double resume" exception
module HTTPMethods
%w[get head post delete put].each do |type|
class_eval %[
def #{type}(options = {}, &blk)
f = Fiber.current
conn = setup_request(:#{type}, options, &blk)
conn.callback { EM.next_tick { f.resume(conn) } }
conn.errback { EM.next_tick { f.resume(conn) } }
Fiber.yield
end
]
end
end
end
class WebMockHttpConnection < HttpConnection
def activate_connection(client)
request_signature = client.request_signature
if client.stubbed_webmock_response
conn = HttpStubConnection.new rand(10000)
post_init
@deferred = false
@conn = conn
conn.parent = self
conn.pending_connect_timeout = @connopts.connect_timeout
conn.comm_inactivity_timeout = @connopts.inactivity_timeout
finalize_request(client)
@conn.set_deferred_status :succeeded
elsif WebMock.net_connect_allowed?(request_signature.uri)
super
else
raise WebMock::NetConnectNotAllowedError.new(request_signature)
end
end
def drop_client
@clients.shift
end
end
class WebMockHttpClient < EventMachine::HttpClient
include HttpEncoding
def uri
@req.uri
end
def setup(response, uri, error = nil)
@last_effective_url = @uri = uri
if error
on_error(error)
@conn.drop_client
fail(self)
else
@conn.receive_data(response)
succeed(self)
end
end
def connection_completed
@state = :response_header
send_request(request_signature.headers, request_signature.body)
end
def send_request(head, body)
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
if stubbed_webmock_response
WebMock::CallbackRegistry.invoke_callbacks({lib: :em_http_request}, request_signature, stubbed_webmock_response)
@uri ||= nil
EM.next_tick {
setup(make_raw_response(stubbed_webmock_response), @uri,
stubbed_webmock_response.should_timeout ? Errno::ETIMEDOUT : nil)
}
self
elsif WebMock.net_connect_allowed?(request_signature.uri)
super
else
raise WebMock::NetConnectNotAllowedError.new(request_signature)
end
end
def unbind(reason = nil)
if !stubbed_webmock_response && WebMock::CallbackRegistry.any_callbacks?
webmock_response = build_webmock_response
WebMock::CallbackRegistry.invoke_callbacks(
{lib: :em_http_request, real_request: true},
request_signature,
webmock_response)
end
@request_signature = nil
remove_instance_variable(:@stubbed_webmock_response)
super
end
def request_signature
@request_signature ||= build_request_signature
end
def stubbed_webmock_response
unless defined?(@stubbed_webmock_response)
@stubbed_webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
end
@stubbed_webmock_response
end
def get_response_cookie(name)
name = name.to_s
raw_cookie = response_header.cookie
raw_cookie = [raw_cookie] if raw_cookie.is_a? String
cookie = raw_cookie.select { |c| c.start_with? name }.first
cookie and cookie.split('=', 2)[1]
end
private
def build_webmock_response
webmock_response = WebMock::Response.new
webmock_response.status = [response_header.status, response_header.http_reason]
webmock_response.headers = response_header
webmock_response.body = response
webmock_response
end
def build_request_signature
headers, body = build_request, @req.body
@conn.middleware.select {|m| m.respond_to?(:request) }.each do |m|
headers, body = m.request(self, headers, body)
end
method = @req.method
uri = @req.uri.clone
query = @req.query
uri.query = encode_query(@req.uri, query).slice(/\?(.*)/, 1)
body = form_encode_body(body) if body.is_a?(Hash)
if headers['authorization'] && headers['authorization'].is_a?(Array)
headers['Authorization'] = WebMock::Util::Headers.basic_auth_header(headers.delete('authorization'))
end
WebMock::RequestSignature.new(
method.downcase.to_sym,
uri.to_s,
body: body || (@req.file && File.read(@req.file)),
headers: headers
)
end
def make_raw_response(response)
response.raise_error_if_any
status, headers, body = response.status, response.headers, response.body
headers ||= {}
response_string = []
response_string << "HTTP/1.1 #{status[0]} #{status[1]}"
headers["Content-Length"] = body.bytesize unless headers["Content-Length"]
headers.each do |header, value|
if header =~ /set-cookie/i
[value].flatten.each do |cookie|
response_string << "#{header}: #{cookie}"
end
else
value = value.join(", ") if value.is_a?(Array)
# WebMock's internal processing will not handle the body
# correctly if the header indicates that it is chunked, unless
# we also create all the chunks.
# It's far easier just to remove the header.
next if header =~ /transfer-encoding/i && value =~/chunked/i
response_string << "#{header}: #{value}"
end
end if headers
response_string << "" << body
response_string.join("\n")
end
end
end
end
webmock-3.18.1/lib/webmock/http_lib_adapters/http_rb/ 0000755 0000041 0000041 00000000000 14333126774 022624 5 ustar www-data www-data webmock-3.18.1/lib/webmock/http_lib_adapters/http_rb/streamer.rb 0000644 0000041 0000041 00000001237 14333126774 024776 0 ustar www-data www-data module HTTP
class Response
class Streamer
def initialize(str, encoding: Encoding::BINARY)
@io = StringIO.new str
@encoding = encoding
end
def readpartial(size = nil, outbuf = nil)
unless size
if defined?(HTTP::Client::BUFFER_SIZE)
size = HTTP::Client::BUFFER_SIZE
elsif defined?(HTTP::Connection::BUFFER_SIZE)
size = HTTP::Connection::BUFFER_SIZE
end
end
chunk = @io.read size, outbuf
chunk.force_encoding(@encoding) if chunk
end
def close
@io.close
end
def sequence_id
-1
end
end
end
end
webmock-3.18.1/lib/webmock/http_lib_adapters/http_rb/client.rb 0000644 0000041 0000041 00000000551 14333126774 024430 0 ustar www-data www-data module HTTP
class Client
alias_method :__perform__, :perform
def perform(request, options)
return __perform__(request, options) unless webmock_enabled?
WebMockPerform.new(request, options) { __perform__(request, options) }.exec
end
def webmock_enabled?
::WebMock::HttpLibAdapters::HttpRbAdapter.enabled?
end
end
end
webmock-3.18.1/lib/webmock/http_lib_adapters/http_rb/request.rb 0000644 0000041 0000041 00000000630 14333126774 024640 0 ustar www-data www-data module HTTP
class Request
def webmock_signature
request_body = if defined?(HTTP::Request::Body)
''.tap { |string| body.each { |part| string << part } }
else
body
end
::WebMock::RequestSignature.new(verb, uri.to_s, {
headers: headers.to_h,
body: request_body
})
end
end
end
webmock-3.18.1/lib/webmock/http_lib_adapters/http_rb/webmock.rb 0000644 0000041 0000041 00000003564 14333126774 024610 0 ustar www-data www-data module HTTP
class WebMockPerform
def initialize(request, options, &perform)
@request = request
@options = options
@perform = perform
@request_signature = nil
end
def exec
replay || perform || halt
end
def request_signature
unless @request_signature
@request_signature = @request.webmock_signature
register_request(@request_signature)
end
@request_signature
end
protected
def response_for_request(signature)
::WebMock::StubRegistry.instance.response_for_request(signature)
end
def register_request(signature)
::WebMock::RequestRegistry.instance.requested_signatures.put(signature)
end
def replay
webmock_response = response_for_request request_signature
return unless webmock_response
raise_timeout_error if webmock_response.should_timeout
webmock_response.raise_error_if_any
invoke_callbacks(webmock_response, real_request: false)
response = ::HTTP::Response.from_webmock @request, webmock_response, request_signature
@options.features.each { |_name, feature| response = feature.wrap_response(response) }
response
end
def raise_timeout_error
raise Errno::ETIMEDOUT if HTTP::VERSION < "1.0.0"
raise HTTP::TimeoutError, "connection error: #{Errno::ETIMEDOUT.new}"
end
def perform
return unless ::WebMock.net_connect_allowed?(request_signature.uri)
response = @perform.call
invoke_callbacks(response.to_webmock, real_request: true)
response
end
def halt
raise ::WebMock::NetConnectNotAllowedError.new request_signature
end
def invoke_callbacks(webmock_response, options = {})
::WebMock::CallbackRegistry.invoke_callbacks(
options.merge({ lib: :http_rb }),
request_signature,
webmock_response
)
end
end
end
webmock-3.18.1/lib/webmock/http_lib_adapters/http_rb/response.rb 0000644 0000041 0000041 00000003602 14333126774 025010 0 ustar www-data www-data module HTTP
class Response
def to_webmock
webmock_response = ::WebMock::Response.new
webmock_response.status = [status.to_i, reason]
webmock_response.body = body.to_s
webmock_response.headers = headers.to_h
webmock_response
end
class << self
def from_webmock(request, webmock_response, request_signature = nil)
status = Status.new(webmock_response.status.first)
headers = webmock_response.headers || {}
uri = normalize_uri(request_signature && request_signature.uri)
# HTTP.rb 3.0+ uses a keyword argument to pass the encoding, but 1.x
# and 2.x use a positional argument, and 0.x don't support supplying
# the encoding.
body = if HTTP::VERSION < "1.0.0"
Body.new(Streamer.new(webmock_response.body))
elsif HTTP::VERSION < "3.0.0"
Body.new(Streamer.new(webmock_response.body), webmock_response.body.encoding)
else
Body.new(
Streamer.new(webmock_response.body, encoding: webmock_response.body.encoding),
encoding: webmock_response.body.encoding
)
end
return new(status, "1.1", headers, body, uri) if HTTP::VERSION < "1.0.0"
# 5.0.0 had a breaking change to require request instead of uri.
if HTTP::VERSION < '5.0.0'
return new({
status: status,
version: "1.1",
headers: headers,
body: body,
uri: uri
})
end
new({
status: status,
version: "1.1",
headers: headers,
body: body,
request: request,
})
end
private
def normalize_uri(uri)
return unless uri
uri = Addressable::URI.parse uri
uri.port = nil if uri.default_port && uri.port == uri.default_port
uri
end
end
end
end
webmock-3.18.1/lib/webmock/http_lib_adapters/patron_adapter.rb 0000644 0000041 0000041 00000011206 14333126774 024512 0 ustar www-data www-data begin
require 'patron'
rescue LoadError
# patron not found
end
if defined?(::Patron)
module WebMock
module HttpLibAdapters
class PatronAdapter < ::WebMock::HttpLibAdapter
adapter_for :patron
OriginalPatronSession = ::Patron::Session unless const_defined?(:OriginalPatronSession)
class WebMockPatronSession < ::Patron::Session
def handle_request(req)
request_signature =
WebMock::HttpLibAdapters::PatronAdapter.build_request_signature(req)
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
if webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
WebMock::HttpLibAdapters::PatronAdapter.
handle_file_name(req, webmock_response)
res = WebMock::HttpLibAdapters::PatronAdapter.
build_patron_response(webmock_response, default_response_charset)
WebMock::CallbackRegistry.invoke_callbacks(
{lib: :patron}, request_signature, webmock_response)
res
elsif WebMock.net_connect_allowed?(request_signature.uri)
res = super
if WebMock::CallbackRegistry.any_callbacks?
webmock_response = WebMock::HttpLibAdapters::PatronAdapter.
build_webmock_response(res)
WebMock::CallbackRegistry.invoke_callbacks(
{lib: :patron, real_request: true}, request_signature,
webmock_response)
end
res
else
raise WebMock::NetConnectNotAllowedError.new(request_signature)
end
end
end
def self.enable!
Patron.send(:remove_const, :Session)
Patron.send(:const_set, :Session, WebMockPatronSession)
end
def self.disable!
Patron.send(:remove_const, :Session)
Patron.send(:const_set, :Session, OriginalPatronSession)
end
def self.handle_file_name(req, webmock_response)
if req.action == :get && req.file_name
begin
File.open(req.file_name, "w") do |f|
f.write webmock_response.body
end
rescue Errno::EACCES
raise ArgumentError.new("Unable to open specified file.")
end
end
end
def self.build_request_signature(req)
uri = WebMock::Util::URI.heuristic_parse(req.url)
uri.path = uri.normalized_path.gsub("[^:]//","/")
if [:put, :post, :patch].include?(req.action)
if req.file_name
if !File.exist?(req.file_name) || !File.readable?(req.file_name)
raise ArgumentError.new("Unable to open specified file.")
end
request_body = File.read(req.file_name)
elsif req.upload_data
request_body = req.upload_data
else
raise ArgumentError.new("Must provide either data or a filename when doing a PUT or POST")
end
end
headers = req.headers
if req.credentials
headers['Authorization'] = WebMock::Util::Headers.basic_auth_header(req.credentials)
end
request_signature = WebMock::RequestSignature.new(
req.action,
uri.to_s,
body: request_body,
headers: headers
)
request_signature
end
def self.build_patron_response(webmock_response, default_response_charset)
raise ::Patron::TimeoutError if webmock_response.should_timeout
webmock_response.raise_error_if_any
header_fields = (webmock_response.headers || []).map { |(k, vs)| Array(vs).map { |v| "#{k}: #{v}" } }.flatten
status_line = "HTTP/1.1 #{webmock_response.status[0]} #{webmock_response.status[1]}"
header_data = ([status_line] + header_fields).join("\r\n")
::Patron::Response.new(
"".dup,
webmock_response.status[0],
0,
header_data,
webmock_response.body.dup,
default_response_charset
)
end
def self.build_webmock_response(patron_response)
webmock_response = WebMock::Response.new
reason = patron_response.status_line.
scan(%r(\AHTTP/(\d+(?:\.\d+)?)\s+(\d\d\d)\s*([^\r\n]+)?))[0][2]
webmock_response.status = [patron_response.status, reason]
webmock_response.body = patron_response.body
webmock_response.headers = patron_response.headers
webmock_response
end
end
end
end
end
webmock-3.18.1/lib/webmock/http_lib_adapters/net_http_response.rb 0000644 0000041 0000041 00000002366 14333126774 025261 0 ustar www-data www-data # This code is entierly copied from VCR (http://github.com/myronmarston/vcr) by courtesy of Myron Marston
# A Net::HTTP response that has already been read raises an IOError when #read_body
# is called with a destination string or block.
#
# This causes a problem when VCR records a response--it reads the body before yielding
# the response, and if the code that is consuming the HTTP requests uses #read_body, it
# can cause an error.
#
# This is a bit of a hack, but it allows a Net::HTTP response to be "re-read"
# after it has aleady been read. This attemps to preserve the behavior of
# #read_body, acting just as if it had never been read.
module Net
module WebMockHTTPResponse
def read_body(dest = nil, &block)
if !(defined?(@__read_body_previously_called).nil?) && @__read_body_previously_called
return super
end
return @body if dest.nil? && block.nil?
raise ArgumentError.new("both arg and block given for HTTP method") if dest && block
return nil if @body.nil?
dest ||= ::Net::ReadAdapter.new(block)
dest << @body.dup
@body = dest
ensure
# allow subsequent calls to #read_body to proceed as normal, without our hack...
@__read_body_previously_called = true
end
end
end
webmock-3.18.1/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb 0000644 0000041 0000041 00000013224 14333126774 026260 0 ustar www-data www-data begin
require 'typhoeus'
rescue LoadError
# typhoeus not found
end
if defined?(Typhoeus)
WebMock::VersionChecker.new('Typhoeus', Typhoeus::VERSION, '0.3.2').check_version!
module WebMock
module HttpLibAdapters
class TyphoeusAdapter < HttpLibAdapter
adapter_for :typhoeus
def self.enable!
@disabled = false
add_before_callback
add_after_request_callback
::Typhoeus::Config.block_connection = true
end
def self.disable!
@disabled = true
remove_after_request_callback
remove_before_callback
::Typhoeus::Config.block_connection = false
end
def self.disabled?
!!@disabled
end
def self.add_before_callback
unless Typhoeus.before.include?(BEFORE_CALLBACK)
Typhoeus.before << BEFORE_CALLBACK
end
end
def self.remove_before_callback
Typhoeus.before.delete_if {|v| v == BEFORE_CALLBACK }
end
def self.add_after_request_callback
unless Typhoeus.on_complete.include?(AFTER_REQUEST_CALLBACK)
Typhoeus.on_complete << AFTER_REQUEST_CALLBACK
end
end
def self.remove_after_request_callback
Typhoeus.on_complete.delete_if {|v| v == AFTER_REQUEST_CALLBACK }
end
def self.build_request_signature(req)
uri = WebMock::Util::URI.heuristic_parse(req.url)
uri.path = uri.normalized_path.gsub("[^:]//","/")
headers = req.options[:headers]
if req.options[:userpwd]
headers['Authorization'] = WebMock::Util::Headers.basic_auth_header(req.options[:userpwd])
end
body = req.options[:body]
if body.is_a?(Hash)
body = WebMock::Util::QueryMapper.values_to_query(body)
end
request_signature = WebMock::RequestSignature.new(
req.options[:method] || :get,
uri.to_s,
body: body,
headers: headers
)
req.instance_variable_set(:@__webmock_request_signature, request_signature)
request_signature
end
def self.build_webmock_response(typhoeus_response)
webmock_response = WebMock::Response.new
webmock_response.status = [typhoeus_response.code, typhoeus_response.status_message]
webmock_response.body = typhoeus_response.body
webmock_response.headers = typhoeus_response.headers
webmock_response
end
def self.generate_typhoeus_response(request_signature, webmock_response)
response = if webmock_response.should_timeout
::Typhoeus::Response.new(
code: 0,
status_message: "",
body: "",
headers: {},
return_code: :operation_timedout
)
else
::Typhoeus::Response.new(
code: webmock_response.status[0],
status_message: webmock_response.status[1],
body: webmock_response.body,
headers: webmock_response.headers,
effective_url: request_signature.uri
)
end
response.mock = :webmock
response
end
def self.request_hash(request_signature)
hash = {}
hash[:body] = request_signature.body
hash[:headers] = request_signature.headers
hash
end
AFTER_REQUEST_CALLBACK = Proc.new do |response|
request = response.request
request_signature = request.instance_variable_get(:@__webmock_request_signature)
webmock_response =
::WebMock::HttpLibAdapters::TyphoeusAdapter.
build_webmock_response(response)
if response.mock
WebMock::CallbackRegistry.invoke_callbacks(
{lib: :typhoeus},
request_signature,
webmock_response
)
else
WebMock::CallbackRegistry.invoke_callbacks(
{lib: :typhoeus, real_request: true},
request_signature,
webmock_response
)
end
end
BEFORE_CALLBACK = Proc.new do |request|
Typhoeus::Expectation.all.delete_if {|e| e.from == :webmock }
res = true
unless WebMock::HttpLibAdapters::TyphoeusAdapter.disabled?
request_signature = ::WebMock::HttpLibAdapters::TyphoeusAdapter.build_request_signature(request)
request.block_connection = false;
::WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
if webmock_response = ::WebMock::StubRegistry.instance.response_for_request(request_signature)
# ::WebMock::HttpLibAdapters::TyphoeusAdapter.stub_typhoeus(request_signature, webmock_response, self)
response = ::WebMock::HttpLibAdapters::TyphoeusAdapter.generate_typhoeus_response(request_signature, webmock_response)
if request.respond_to?(:on_headers)
request.execute_headers_callbacks(response)
end
if request.respond_to?(:streaming?) && request.streaming?
response.options[:response_body] = ""
request.on_body.each { |callback| callback.call(webmock_response.body, response) }
end
request.finish(response)
webmock_response.raise_error_if_any
res = false
elsif !WebMock.net_connect_allowed?(request_signature.uri)
raise WebMock::NetConnectNotAllowedError.new(request_signature)
end
end
res
end
end
end
end
end
webmock-3.18.1/lib/webmock/http_lib_adapters/http_lib_adapter.rb 0000644 0000041 0000041 00000000230 14333126774 025007 0 ustar www-data www-data module WebMock
class HttpLibAdapter
def self.adapter_for(lib)
WebMock::HttpLibAdapterRegistry.instance.register(lib, self)
end
end
end webmock-3.18.1/lib/webmock/http_lib_adapters/httpclient_adapter.rb 0000644 0000041 0000041 00000020134 14333126774 025365 0 ustar www-data www-data begin
require 'httpclient'
require 'jsonclient' # defined in 'httpclient' gem as well
rescue LoadError
# httpclient not found
# or jsonclient not defined (in old versions of httclient gem)
end
if defined?(::HTTPClient)
module WebMock
module HttpLibAdapters
class HTTPClientAdapter < HttpLibAdapter
adapter_for :httpclient
unless const_defined?(:OriginalHttpClient)
OriginalHttpClient = ::HTTPClient
end
unless const_defined?(:OriginalJsonClient)
OriginalJsonClient = ::JSONClient if defined?(::JSONClient)
end
def self.enable!
Object.send(:remove_const, :HTTPClient)
Object.send(:const_set, :HTTPClient, WebMockHTTPClient)
if defined? ::JSONClient
Object.send(:remove_const, :JSONClient)
Object.send(:const_set, :JSONClient, WebMockJSONClient)
end
end
def self.disable!
Object.send(:remove_const, :HTTPClient)
Object.send(:const_set, :HTTPClient, OriginalHttpClient)
if defined? ::JSONClient
Object.send(:remove_const, :JSONClient)
Object.send(:const_set, :JSONClient, OriginalJsonClient)
end
end
end
end
end
module WebMockHTTPClients
REQUEST_RESPONSE_LOCK = Mutex.new
def do_get_block(req, proxy, conn, &block)
do_get(req, proxy, conn, false, &block)
end
def do_get_stream(req, proxy, conn, &block)
do_get(req, proxy, conn, true, &block)
end
def do_get(req, proxy, conn, stream = false, &block)
request_signature = build_request_signature(req, :reuse_existing)
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
if webmock_responses[request_signature]
webmock_response = synchronize_request_response { webmock_responses.delete(request_signature) }
response = build_httpclient_response(webmock_response, stream, req.header, &block)
@request_filter.each do |filter|
filter.filter_response(req, response)
end
res = conn.push(response)
WebMock::CallbackRegistry.invoke_callbacks(
{lib: :httpclient}, request_signature, webmock_response)
res
elsif WebMock.net_connect_allowed?(request_signature.uri)
# in case there is a nil entry in the hash...
synchronize_request_response { webmock_responses.delete(request_signature) }
res = if stream
do_get_stream_without_webmock(req, proxy, conn, &block)
elsif block
body = ''
do_get_block_without_webmock(req, proxy, conn) do |http_res, chunk|
if chunk && chunk.bytesize > 0
body += chunk
block.call(http_res, chunk)
end
end
else
do_get_block_without_webmock(req, proxy, conn)
end
res = conn.pop
conn.push(res)
if WebMock::CallbackRegistry.any_callbacks?
webmock_response = build_webmock_response(res, body)
WebMock::CallbackRegistry.invoke_callbacks(
{lib: :httpclient, real_request: true}, request_signature,
webmock_response)
end
res
else
raise WebMock::NetConnectNotAllowedError.new(request_signature)
end
end
def do_request_async(method, uri, query, body, extheader)
req = create_request(method, uri, query, body, extheader)
request_signature = build_request_signature(req)
synchronize_request_response { webmock_request_signatures << request_signature }
if webmock_responses[request_signature] || WebMock.net_connect_allowed?(request_signature.uri)
super
else
raise WebMock::NetConnectNotAllowedError.new(request_signature)
end
end
def build_httpclient_response(webmock_response, stream = false, req_header = nil, &block)
body = stream ? StringIO.new(webmock_response.body) : webmock_response.body
response = HTTP::Message.new_response(body, req_header)
response.header.init_response(webmock_response.status[0])
response.reason=webmock_response.status[1]
webmock_response.headers.to_a.each { |name, value| response.header.set(name, value) }
raise HTTPClient::TimeoutError if webmock_response.should_timeout
webmock_response.raise_error_if_any
block.call(response, body) if block && body && body.bytesize > 0
response
end
def build_webmock_response(httpclient_response, body = nil)
webmock_response = WebMock::Response.new
webmock_response.status = [httpclient_response.status, httpclient_response.reason]
webmock_response.headers = {}.tap do |hash|
httpclient_response.header.all.each do |(key, value)|
if hash.has_key?(key)
hash[key] = Array(hash[key]) + [value]
else
hash[key] = value
end
end
end
if body
webmock_response.body = body
elsif httpclient_response.content.respond_to?(:read)
webmock_response.body = httpclient_response.content.read
body = HTTP::Message::Body.new
body.init_response(StringIO.new(webmock_response.body))
httpclient_response.body = body
else
webmock_response.body = httpclient_response.content
end
webmock_response
end
def build_request_signature(req, reuse_existing = false)
uri = WebMock::Util::URI.heuristic_parse(req.header.request_uri.to_s)
uri.query = WebMock::Util::QueryMapper.values_to_query(req.header.request_query, notation: WebMock::Config.instance.query_values_notation) if req.header.request_query
uri.port = req.header.request_uri.port
@request_filter.each do |filter|
filter.filter_request(req)
end
headers = req.header.all.inject({}) do |hdrs, header|
hdrs[header[0]] ||= []
hdrs[header[0]] << header[1]
hdrs
end
headers = headers_from_session(uri).merge(headers)
signature = WebMock::RequestSignature.new(
req.header.request_method.downcase.to_sym,
uri.to_s,
body: req.http_body.dump,
headers: headers
)
# reuse a previous identical signature object if we stored one for later use
if reuse_existing && previous_signature = previous_signature_for(signature)
return previous_signature
end
signature
end
def webmock_responses
@webmock_responses ||= Hash.new do |hash, request_signature|
synchronize_request_response do
hash[request_signature] = WebMock::StubRegistry.instance.response_for_request(request_signature)
end
end
end
def webmock_request_signatures
@webmock_request_signatures ||= []
end
def previous_signature_for(signature)
synchronize_request_response do
return nil unless index = webmock_request_signatures.index(signature)
webmock_request_signatures.delete_at(index)
end
end
private
# some of the headers sent by HTTPClient are derived from
# the client session
def headers_from_session(uri)
session_headers = HTTP::Message::Headers.new
@session_manager.send(:open, uri).send(:set_header, MessageMock.new(session_headers))
session_headers.all.inject({}) do |hdrs, header|
hdrs[header[0]] = header[1]
hdrs
end
end
def synchronize_request_response
if REQUEST_RESPONSE_LOCK.owned?
yield
else
REQUEST_RESPONSE_LOCK.synchronize do
yield
end
end
end
end
class WebMockHTTPClient < HTTPClient
alias_method :do_get_block_without_webmock, :do_get_block
alias_method :do_get_stream_without_webmock, :do_get_stream
include WebMockHTTPClients
end
if defined? ::JSONClient
class WebMockJSONClient < JSONClient
alias_method :do_get_block_without_webmock, :do_get_block
alias_method :do_get_stream_without_webmock, :do_get_stream
include WebMockHTTPClients
end
end
# Mocks a HTTPClient HTTP::Message
class MessageMock
attr_reader :header
def initialize(headers)
@header = headers
end
def http_version=(value);end
end
end
webmock-3.18.1/lib/webmock/request_signature.rb 0000644 0000041 0000041 00000002507 14333126774 021574 0 ustar www-data www-data module WebMock
class RequestSignature
attr_accessor :method, :uri, :body
attr_reader :headers
def initialize(method, uri, options = {})
self.method = method.to_sym
self.uri = uri.is_a?(Addressable::URI) ? uri : WebMock::Util::URI.normalize_uri(uri)
assign_options(options)
end
def to_s
string = "#{self.method.to_s.upcase}".dup
string << " #{WebMock::Util::URI.strip_default_port_from_uri_string(self.uri.to_s)}"
string << " with body '#{body.to_s}'" if body && body.to_s != ''
if headers && !headers.empty?
string << " with headers #{WebMock::Util::Headers.sorted_headers_string(headers)}"
end
string
end
def headers=(headers)
@headers = WebMock::Util::Headers.normalize_headers(headers)
end
def hash
self.to_s.hash
end
def eql?(other)
self.to_s == other.to_s
end
alias == eql?
def url_encoded?
!!(headers&.fetch('Content-Type', nil)&.start_with?('application/x-www-form-urlencoded'))
end
def json_headers?
!!(headers&.fetch('Content-Type', nil)&.start_with?('application/json'))
end
private
def assign_options(options)
self.body = options[:body] if options.has_key?(:body)
self.headers = options[:headers] if options.has_key?(:headers)
end
end
end
webmock-3.18.1/lib/webmock/rack_response.rb 0000644 0000041 0000041 00000003370 14333126774 020660 0 ustar www-data www-data module WebMock
class RackResponse < Response
def initialize(app)
@app = app
end
def evaluate(request)
env = build_rack_env(request)
status, headers, response = @app.call(env)
Response.new(
body: body_from_rack_response(response),
headers: headers,
status: [status, Rack::Utils::HTTP_STATUS_CODES[status]]
)
end
def body_from_rack_response(response)
body = "".dup
response.each { |line| body << line }
response.close if response.respond_to?(:close)
return body
end
def build_rack_env(request)
uri = request.uri
headers = (request.headers || {}).dup
body = request.body || ''
env = {
# CGI variables specified by Rack
'REQUEST_METHOD' => request.method.to_s.upcase,
'CONTENT_TYPE' => headers.delete('Content-Type'),
'CONTENT_LENGTH' => body.bytesize,
'PATH_INFO' => uri.path,
'QUERY_STRING' => uri.query || '',
'SERVER_NAME' => uri.host,
'SERVER_PORT' => uri.port,
'SCRIPT_NAME' => ""
}
env['HTTP_AUTHORIZATION'] = 'Basic ' + [uri.userinfo].pack('m').delete("\r\n") if uri.userinfo
# Rack-specific variables
env['rack.input'] = StringIO.new(body)
env['rack.errors'] = $stderr
env['rack.version'] = Rack::VERSION
env['rack.url_scheme'] = uri.scheme
env['rack.run_once'] = true
env['rack.session'] = session
env['rack.session.options'] = session_options
headers.each do |k, v|
env["HTTP_#{k.tr('-','_').upcase}"] = v
end
env
end
def session
@session ||= {}
end
def session_options
@session_options ||= {}
end
end
end
webmock-3.18.1/lib/webmock/config.rb 0000644 0000041 0000041 00000000650 14333126774 017265 0 ustar www-data www-data module WebMock
class Config
include Singleton
def initialize
@show_stubbing_instructions = true
@show_body_diff = true
end
attr_accessor :allow_net_connect
attr_accessor :allow_localhost
attr_accessor :allow
attr_accessor :net_http_connect_on_start
attr_accessor :show_stubbing_instructions
attr_accessor :query_values_notation
attr_accessor :show_body_diff
end
end
webmock-3.18.1/lib/webmock/request_stub.rb 0000644 0000041 0000041 00000006233 14333126774 020550 0 ustar www-data www-data module WebMock
class RequestStub
attr_accessor :request_pattern
def initialize(method, uri)
@request_pattern = RequestPattern.new(method, uri)
@responses_sequences = []
self
end
def with(params = {}, &block)
@request_pattern.with(params, &block)
self
end
def to_return(*response_hashes, &block)
if block
@responses_sequences << ResponsesSequence.new([ResponseFactory.response_for(block)])
else
@responses_sequences << ResponsesSequence.new([*response_hashes].flatten.map {|r| ResponseFactory.response_for(r)})
end
self
end
alias_method :and_return, :to_return
def to_return_json(*response_hashes)
raise ArgumentError, '#to_return_json does not support passing a block' if block_given?
json_response_hashes = [*response_hashes].flatten.map do |resp_h|
headers, body = resp_h.values_at(:headers, :body)
resp_h.merge(
headers: {content_type: 'application/json'}.merge(headers.to_h),
body: body.is_a?(Hash) ? body.to_json : body
)
end
to_return(json_response_hashes)
end
alias_method :and_return_json, :to_return_json
def to_rack(app, options={})
@responses_sequences << ResponsesSequence.new([RackResponse.new(app)])
end
def to_raise(*exceptions)
@responses_sequences << ResponsesSequence.new([*exceptions].flatten.map {|e|
ResponseFactory.response_for(exception: e)
})
self
end
alias_method :and_raise, :to_raise
def to_timeout
@responses_sequences << ResponsesSequence.new([ResponseFactory.response_for(should_timeout: true)])
self
end
alias_method :and_timeout, :to_timeout
def response
if @responses_sequences.empty?
WebMock::Response.new
elsif @responses_sequences.length > 1
@responses_sequences.shift if @responses_sequences.first.end?
@responses_sequences.first.next_response
else
@responses_sequences[0].next_response
end
end
def has_responses?
!@responses_sequences.empty?
end
def then
self
end
def times(number)
raise "times(N) accepts integers >= 1 only" if !number.is_a?(Integer) || number < 1
if @responses_sequences.empty?
raise "Invalid WebMock stub declaration." +
" times(N) can be declared only after response declaration."
end
@responses_sequences.last.times_to_repeat += number-1
self
end
def matches?(request_signature)
self.request_pattern.matches?(request_signature)
end
def to_s
self.request_pattern.to_s
end
def self.from_request_signature(signature)
stub = self.new(signature.method.to_sym, signature.uri.to_s)
if signature.body.to_s != ''
body = if signature.url_encoded?
WebMock::Util::QueryMapper.query_to_values(signature.body, notation: Config.instance.query_values_notation)
else
signature.body
end
stub.with(body: body)
end
if (signature.headers && !signature.headers.empty?)
stub.with(headers: signature.headers)
end
stub
end
end
end
webmock-3.18.1/lib/webmock/rspec.rb 0000644 0000041 0000041 00000001622 14333126774 017134 0 ustar www-data www-data require 'webmock'
# RSpec 1.x and 2.x compatibility
if defined?(RSpec::Expectations::ExpectationNotMetError)
RSPEC_NAMESPACE = RSPEC_CONFIGURER = RSpec
elsif defined?(Spec) && defined?(Spec.configure)
RSPEC_NAMESPACE = Spec
RSPEC_CONFIGURER = Spec::Runner
else
begin
require 'rspec/core'
require 'rspec/expectations'
RSPEC_NAMESPACE = RSPEC_CONFIGURER = RSpec
rescue LoadError
require 'spec'
RSPEC_NAMESPACE = Spec
RSPEC_CONFIGURER = Spec::Runner
end
end
require 'webmock/rspec/matchers'
RSPEC_CONFIGURER.configure { |config|
config.include WebMock::API
config.include WebMock::Matchers
config.before(:suite) do
WebMock.enable!
end
config.after(:suite) do
WebMock.disable!
end
config.around(:each) do |example|
example.run
WebMock.reset!
end
}
WebMock::AssertionFailure.error_class = RSPEC_NAMESPACE::Expectations::ExpectationNotMetError
webmock-3.18.1/lib/webmock/test_unit.rb 0000644 0000041 0000041 00000000456 14333126774 020042 0 ustar www-data www-data require 'test/unit'
require 'webmock'
WebMock.enable!
module Test
module Unit
class TestCase
include WebMock::API
teardown
def teardown_with_webmock
WebMock.reset!
end
end
end
end
WebMock::AssertionFailure.error_class = Test::Unit::AssertionFailedError
webmock-3.18.1/lib/webmock.rb 0000644 0000041 0000041 00000004434 14333126774 016024 0 ustar www-data www-data require 'singleton'
require 'addressable/uri'
require 'addressable/template'
require 'crack/xml'
require_relative 'webmock/deprecation'
require_relative 'webmock/version'
require_relative 'webmock/errors'
require_relative 'webmock/util/query_mapper'
require_relative 'webmock/util/uri'
require_relative 'webmock/util/headers'
require_relative 'webmock/util/hash_counter'
require_relative 'webmock/util/hash_keys_stringifier'
require_relative 'webmock/util/values_stringifier'
require_relative 'webmock/util/json'
require_relative 'webmock/util/version_checker'
require_relative 'webmock/util/hash_validator'
require_relative 'webmock/matchers/hash_argument_matcher'
require_relative 'webmock/matchers/hash_excluding_matcher'
require_relative 'webmock/matchers/hash_including_matcher'
require_relative 'webmock/matchers/any_arg_matcher'
require_relative 'webmock/request_pattern'
require_relative 'webmock/request_signature'
require_relative 'webmock/responses_sequence'
require_relative 'webmock/request_stub'
require_relative 'webmock/response'
require_relative 'webmock/rack_response'
require_relative 'webmock/stub_request_snippet'
require_relative 'webmock/request_signature_snippet'
require_relative 'webmock/request_body_diff'
require_relative 'webmock/assertion_failure'
require_relative 'webmock/request_execution_verifier'
require_relative 'webmock/config'
require_relative 'webmock/callback_registry'
require_relative 'webmock/request_registry'
require_relative 'webmock/stub_registry'
require_relative 'webmock/api'
require_relative 'webmock/http_lib_adapters/http_lib_adapter_registry'
require_relative 'webmock/http_lib_adapters/http_lib_adapter'
require_relative 'webmock/http_lib_adapters/net_http'
require_relative 'webmock/http_lib_adapters/http_rb_adapter'
require_relative 'webmock/http_lib_adapters/httpclient_adapter'
require_relative 'webmock/http_lib_adapters/patron_adapter'
require_relative 'webmock/http_lib_adapters/curb_adapter'
require_relative 'webmock/http_lib_adapters/em_http_request_adapter'
require_relative 'webmock/http_lib_adapters/typhoeus_hydra_adapter'
require_relative 'webmock/http_lib_adapters/excon_adapter'
require_relative 'webmock/http_lib_adapters/manticore_adapter'
require_relative 'webmock/http_lib_adapters/async_http_client_adapter'
require_relative 'webmock/webmock'
webmock-3.18.1/Gemfile 0000644 0000041 0000041 00000000143 14333126774 014566 0 ustar www-data www-data source 'https://rubygems.org/'
gemspec
gem 'rake'
platforms :jruby do
gem 'jruby-openssl'
end
webmock-3.18.1/.github/ 0000755 0000041 0000041 00000000000 14333126774 014635 5 ustar www-data www-data webmock-3.18.1/.github/workflows/ 0000755 0000041 0000041 00000000000 14333126774 016672 5 ustar www-data www-data webmock-3.18.1/.github/workflows/CI.yml 0000644 0000041 0000041 00000001377 14333126774 017720 0 ustar www-data www-data name: CI
on:
push:
branches:
- master
pull_request:
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
ruby:
- head
- '3.1'
- '3.0'
- '2.7'
- '2.6'
- '2.5'
- jruby
continue-on-error: ${{ matrix.ruby == 'head' }}
name: Ruby ${{ matrix.ruby }}
env:
JRUBY_OPTS: "--debug"
steps:
- uses: actions/checkout@v2
- name: Install Apt Packages
run: |
sudo apt-get install libcurl4-openssl-dev -y
- uses: ruby/setup-ruby@v1
continue-on-error: true
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
- run: |
bundle exec rake
webmock-3.18.1/.rspec-tm 0000644 0000041 0000041 00000000037 14333126774 015030 0 ustar www-data www-data --rspec-version 2.0.0
--bundler