webmock 1.21.0 → 1.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. data/.travis.yml +8 -0
  2. data/CHANGELOG.md +51 -1
  3. data/Gemfile +0 -1
  4. data/README.md +17 -6
  5. data/lib/webmock.rb +4 -1
  6. data/lib/webmock/config.rb +2 -0
  7. data/lib/webmock/errors.rb +3 -21
  8. data/lib/webmock/http_lib_adapters/em_http_request/em_http_request_1_x.rb +5 -0
  9. data/lib/webmock/http_lib_adapters/manticore_adapter.rb +123 -0
  10. data/lib/webmock/http_lib_adapters/net_http.rb +16 -2
  11. data/lib/webmock/request_body_diff.rb +63 -0
  12. data/lib/webmock/request_execution_verifier.rb +24 -21
  13. data/lib/webmock/request_pattern.rb +2 -0
  14. data/lib/webmock/request_signature.rb +5 -1
  15. data/lib/webmock/request_signature_snippet.rb +61 -0
  16. data/lib/webmock/rspec/matchers.rb +0 -1
  17. data/lib/webmock/rspec/matchers/request_pattern_matcher.rb +4 -0
  18. data/lib/webmock/rspec/matchers/webmock_matcher.rb +4 -0
  19. data/lib/webmock/stub_request_snippet.rb +4 -0
  20. data/lib/webmock/util/json.rb +25 -6
  21. data/lib/webmock/util/query_mapper.rb +6 -4
  22. data/lib/webmock/version.rb +1 -1
  23. data/lib/webmock/webmock.rb +12 -0
  24. data/spec/acceptance/em_http_request/em_http_request_spec.rb +60 -0
  25. data/spec/acceptance/http_rb/http_rb_spec.rb +2 -2
  26. data/spec/acceptance/http_rb/http_rb_spec_helper.rb +1 -1
  27. data/spec/acceptance/httpclient/httpclient_spec.rb +8 -7
  28. data/spec/acceptance/manticore/manticore_spec.rb +56 -0
  29. data/spec/acceptance/manticore/manticore_spec_helper.rb +31 -0
  30. data/spec/acceptance/net_http/net_http_spec.rb +24 -1
  31. data/spec/acceptance/shared/request_expectations.rb +10 -10
  32. data/spec/spec_helper.rb +4 -0
  33. data/spec/unit/errors_spec.rb +45 -4
  34. data/spec/unit/request_body_diff_spec.rb +90 -0
  35. data/spec/unit/request_execution_verifier_spec.rb +48 -11
  36. data/spec/unit/request_signature_snippet_spec.rb +89 -0
  37. data/spec/unit/request_signature_spec.rb +61 -23
  38. data/spec/unit/stub_registry_spec.rb +1 -1
  39. data/spec/unit/util/json_spec.rb +29 -3
  40. data/spec/unit/util/query_mapper_spec.rb +15 -4
  41. data/spec/unit/webmock_spec.rb +4 -0
  42. data/test/shared_test.rb +2 -2
  43. data/webmock.gemspec +4 -1
  44. metadata +63 -24
data/.travis.yml CHANGED
@@ -5,14 +5,22 @@ rvm:
5
5
  - 2.0.0
6
6
  - 2.1.0
7
7
  - 2.2.1
8
+ - 2.2.3
9
+ - rbx-2
8
10
  - ruby-head
9
11
  - ree
12
+ - jruby-9.0.0.0
13
+ - jruby-9.0.1.0
10
14
  - jruby-18mode
11
15
  - jruby-19mode
12
16
  - jruby
13
17
  - jruby-head
14
18
  matrix:
15
19
  allow_failures:
20
+ - rvm: jruby-9.0.0.0
21
+ - rvm: jruby-9.0.1.0
16
22
  - rvm: jruby-18mode
17
23
  - rvm: jruby-head
18
24
  - rvm: ruby-head
25
+ - rvm: rbx-2
26
+ sudo: false
data/CHANGELOG.md CHANGED
@@ -1,5 +1,55 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.22.1
4
+
5
+ * Adds Rack as a development dependency and removes require rack/utils in main lib.
6
+
7
+ Thanks to [Keenan Brock](https://github.com/kbrock)
8
+
9
+ ## 1.22.0
10
+
11
+ All the credit for preparing this release go to [David Begin](https://github.com/davidbegin)!
12
+
13
+ * Adds [Manticore](https://github.com/cheald/manticore) support.
14
+
15
+ Thanks to [Mike Knepper](https://github.com/mikeknep), [David Abdemoulaie](https://github.com/hobodave)
16
+
17
+ * Update to Show a hash diff for requests that have stubs with a body.
18
+
19
+ Thanks to [yurivm](https://github.com/yurivm)
20
+
21
+ * Update to mirror Net::HTTP handling of headers as symbols
22
+
23
+ * Update to ignore non-comparable-values error when sorting
24
+ query values, because sorting is just a convience.
25
+
26
+ Thanks to [Magne Land](https://github.com/magneland)
27
+
28
+ * Covert Boolean values to Strings when using them to define
29
+ the body of a request.
30
+
31
+ Thanks to [Krzysztof Rygielski](https://github.com/riggy)
32
+
33
+ * Fixes WebMock's parsing Multibyte characters
34
+
35
+ Thanks to [Zhao Wen](https://github.com/VincentZhao)
36
+
37
+ * Updates to be compatible with httpclient 2.6.0
38
+
39
+ * Converts keys from symbols to strings when for QueryMapper.to_query
40
+
41
+ Thanks to [Ramon Tayag](https://github.com/ramontayag)
42
+
43
+ * Restricts http.rb version to 0.7.3 for Ruby 1.8.7
44
+
45
+ * Fixes issue emulating em-http-request's handling of multiple requests.
46
+
47
+ Thanks to [Matt Palmer](https://github.com/mpalmer)
48
+
49
+ * WebMock requires only the necessary parts of crack to avoid pulling in safe_yaml
50
+
51
+ Thanks to [Johannes Schlumberger](https://github.com/spjsschl)
52
+
3
53
  ## 1.21.0
4
54
 
5
55
  * Support for http.rb >= 0.8.0
@@ -10,7 +60,7 @@
10
60
 
11
61
  Thanks to [Mattias Putman](https://github.com/challengee)
12
62
 
13
- * Added support for RSpec3-like `and_return`, `and_raise`, `and_timeout` sytnax.
63
+ * Added support for RSpec3-like `and_return`, `and_raise`, `and_timeout` syntax.
14
64
 
15
65
  Thanks to [Franky Wahl](https://github.com/frankywahl)
16
66
 
data/Gemfile CHANGED
@@ -10,7 +10,6 @@ group :development do
10
10
  end
11
11
 
12
12
  group :test do
13
- gem 'rack'
14
13
  gem 'minitest_tu_shim', '1.3.2'
15
14
  end
16
15
 
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
- WebMock [![Build Status](https://secure.travis-ci.org/bblimke/webmock.png?branch=master)](http://travis-ci.org/bblimke/webmock) [![Dependency Status](https://gemnasium.com/bblimke/webmock.png)](http://gemnasium.com/bblimke/webmock)
1
+ WebMock
2
2
  =======
3
+ [![Gem Version](https://badge.fury.io/rb/webmock.svg)](http://badge.fury.io/rb/webmock) [![Build Status](https://secure.travis-ci.org/bblimke/webmock.svg?branch=master)](http://travis-ci.org/bblimke/webmock) [![Dependency Status](https://gemnasium.com/bblimke/webmock.svg)](http://gemnasium.com/bblimke/webmock) [![Code Climate](https://codeclimate.com/github/bblimke/webmock/badges/gpa.svg)](https://codeclimate.com/github/bblimke/webmock) [![Inline docs](http://inch-ci.org/github/bblimke/webmock.svg?branch=master)](http://inch-ci.org/github/bblimke/webmock)
3
4
 
4
5
  Library for stubbing and setting expectations on HTTP requests in Ruby.
5
6
 
@@ -26,6 +27,7 @@ Supported HTTP libraries
26
27
  * Typhoeus (currently only Typhoeus::Hydra)
27
28
  * Excon
28
29
  * HTTP Gem
30
+ * Manticore
29
31
 
30
32
  Supported Ruby Interpreters
31
33
  ---------------------------
@@ -736,13 +738,13 @@ If you use any of the WebMock methods for matching query params, then Addressabl
736
738
  WebMock will match request headers against stubbed request headers in the following situations:
737
739
 
738
740
  1. Stubbed request has headers specified and request headers are the same as stubbed headers <br/>
739
- i.e stubbed headers: `{ 'Header1' => 'Value1', 'Header1' => 'Value1' }`, requested: `{ 'Header1' => 'Value1', 'Header1' => 'Value1' }`
741
+ i.e stubbed headers: `{ 'Header1' => 'Value1', 'Header2' => 'Value2' }`, requested: `{ 'Header1' => 'Value1', 'Header2' => 'Value2' }`
740
742
 
741
743
  2. Stubbed request has headers specified and stubbed request headers are a subset of request headers <br/>
742
- i.e stubbed headers: `{ 'Header1' => 'Value1' }`, requested: `{ 'Header1' => 'Value1', 'Header1' => 'Value1' }`
744
+ i.e stubbed headers: `{ 'Header1' => 'Value1' }`, requested: `{ 'Header1' => 'Value1', 'Header2' => 'Value2' }`
743
745
 
744
746
  3. Stubbed request has no headers <br/>
745
- i.e stubbed headers: `nil`, requested: `{ 'Header1' => 'Value1', 'Header1' => 'Value1' }`
747
+ i.e stubbed headers: `nil`, requested: `{ 'Header1' => 'Value1', 'Header2' => 'Value2' }`
746
748
 
747
749
  WebMock normalises headers and treats all forms of same headers as equal:
748
750
  i.e the following two sets of headers are equal:
@@ -827,7 +829,7 @@ all version with just one command.
827
829
 
828
830
  This command is wrapped up in to a rake task and can be invoked like so:
829
831
 
830
- rake spec:rubies
832
+ rake rvm:specs
831
833
 
832
834
  ## Credits
833
835
 
@@ -972,7 +974,16 @@ People who submitted patches and new features or suggested improvements. Many th
972
974
  * Steve Mitchell
973
975
  * Mattias Putman
974
976
  * Zachary Anker
975
-
977
+ * Emmanuel Sambo
978
+ * Ramon Tayag
979
+ * Johannes Schlumberger
980
+ * Siôn Le Roux
981
+ * Matt Palmer
982
+ * Zhao Wen
983
+ * Krzysztof Rygielski
984
+ * Magne Land
985
+ * yurivm
986
+ * Mike Knepper
976
987
 
977
988
  For a full list of contributors you can visit the
978
989
  [contributors](https://github.com/bblimke/webmock/contributors) page.
data/lib/webmock.rb CHANGED
@@ -2,7 +2,7 @@ require 'singleton'
2
2
 
3
3
  require 'addressable/uri'
4
4
  require 'addressable/template'
5
- require 'crack'
5
+ require 'crack/xml'
6
6
 
7
7
  require 'webmock/deprecation'
8
8
  require 'webmock/version'
@@ -28,6 +28,8 @@ require 'webmock/response'
28
28
  require 'webmock/rack_response'
29
29
 
30
30
  require 'webmock/stub_request_snippet'
31
+ require 'webmock/request_signature_snippet'
32
+ require 'webmock/request_body_diff'
31
33
 
32
34
  require 'webmock/assertion_failure'
33
35
  require 'webmock/request_execution_verifier'
@@ -47,6 +49,7 @@ require 'webmock/http_lib_adapters/curb_adapter'
47
49
  require 'webmock/http_lib_adapters/em_http_request_adapter'
48
50
  require 'webmock/http_lib_adapters/typhoeus_hydra_adapter'
49
51
  require 'webmock/http_lib_adapters/excon_adapter'
52
+ require 'webmock/http_lib_adapters/manticore_adapter'
50
53
 
51
54
  require 'webmock/webmock'
52
55
 
@@ -4,6 +4,7 @@ module WebMock
4
4
 
5
5
  def initialize
6
6
  @show_stubbing_instructions = true
7
+ @show_body_diff = true
7
8
  end
8
9
 
9
10
  attr_accessor :allow_net_connect
@@ -12,5 +13,6 @@ module WebMock
12
13
  attr_accessor :net_http_connect_on_start
13
14
  attr_accessor :show_stubbing_instructions
14
15
  attr_accessor :query_values_notation
16
+ attr_accessor :show_body_diff
15
17
  end
16
18
  end
@@ -2,34 +2,16 @@ module WebMock
2
2
 
3
3
  class NetConnectNotAllowedError < Exception
4
4
  def initialize(request_signature)
5
+ request_signature_snippet = RequestSignatureSnippet.new(request_signature)
5
6
  text = [
6
7
  "Real HTTP connections are disabled. Unregistered request: #{request_signature}",
7
- stubbing_instructions(request_signature),
8
- request_stubs,
8
+ request_signature_snippet.stubbing_instructions,
9
+ request_signature_snippet.request_stubs,
9
10
  "="*60
10
11
  ].compact.join("\n\n")
11
12
  super(text)
12
13
  end
13
14
 
14
- private
15
-
16
- def request_stubs
17
- return if WebMock::StubRegistry.instance.request_stubs.empty?
18
- text = "registered request stubs:\n"
19
- WebMock::StubRegistry.instance.request_stubs.each do |stub|
20
- text << "\n#{WebMock::StubRequestSnippet.new(stub).to_s(false)}"
21
- end
22
- text
23
- end
24
-
25
- def stubbing_instructions(request_signature)
26
- return unless WebMock.show_stubbing_instructions?
27
- text = ""
28
- request_stub = RequestStub.from_request_signature(request_signature)
29
- text << "You can stub this request with the following snippet:\n\n"
30
- text << WebMock::StubRequestSnippet.new(request_stub).to_s
31
- text
32
- end
33
15
  end
34
16
 
35
17
  end
@@ -70,6 +70,10 @@ if defined?(EventMachine::HttpClient)
70
70
  raise WebMock::NetConnectNotAllowedError.new(request_signature)
71
71
  end
72
72
  end
73
+
74
+ def drop_client
75
+ @clients.shift
76
+ end
73
77
  end
74
78
 
75
79
  class WebMockHttpClient < EventMachine::HttpClient
@@ -83,6 +87,7 @@ if defined?(EventMachine::HttpClient)
83
87
  @last_effective_url = @uri = uri
84
88
  if error
85
89
  on_error(error)
90
+ @conn.drop_client
86
91
  fail(self)
87
92
  else
88
93
  @conn.receive_data(response)
@@ -0,0 +1,123 @@
1
+ begin
2
+ require 'manticore'
3
+ rescue LoadError
4
+ # manticore not found
5
+ end
6
+
7
+ if defined?(Manticore)
8
+ module WebMock
9
+ module HttpLibAdapters
10
+ class ManticoreAdapter < HttpLibAdapter
11
+ adapter_for :manticore
12
+
13
+ OriginalManticoreClient = Manticore::Client
14
+
15
+ def self.enable!
16
+ Manticore.send(:remove_const, :Client)
17
+ Manticore.send(:const_set, :Client, WebMockManticoreClient)
18
+ Manticore.instance_variable_set(:@manticore_facade, WebMockManticoreClient.new)
19
+ end
20
+
21
+ def self.disable!
22
+ Manticore.send(:remove_const, :Client)
23
+ Manticore.send(:const_set, :Client, OriginalManticoreClient)
24
+ Manticore.instance_variable_set(:@manticore_facade, OriginalManticoreClient.new)
25
+ end
26
+
27
+ class WebMockManticoreClient < Manticore::Client
28
+ def request(klass, url, options={}, &block)
29
+ super(klass, WebMock::Util::URI.normalize_uri(url).to_s, format_options(options))
30
+ end
31
+
32
+ private
33
+
34
+ def format_options(options)
35
+ return options unless headers = options[:headers]
36
+
37
+ options.merge(:headers => join_array_values(headers))
38
+ end
39
+
40
+ def join_array_values(headers)
41
+ headers.reduce({}) do |h, (k,v)|
42
+ v = v.join(', ') if v.is_a?(Array)
43
+ h.merge(k => v)
44
+ end
45
+ end
46
+
47
+ def response_object_for(request, context, &block)
48
+ request_signature = generate_webmock_request_signature(request)
49
+ WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
50
+
51
+ if webmock_response = registered_response_for(request_signature)
52
+ webmock_response.raise_error_if_any
53
+ manticore_response = generate_manticore_response(webmock_response).call
54
+ real_request = false
55
+
56
+ elsif real_request_allowed?(request_signature.uri)
57
+ manticore_response = Manticore::Response.new(self, request, context, &block).call
58
+ webmock_response = generate_webmock_response(manticore_response)
59
+ real_request = true
60
+
61
+ else
62
+ raise WebMock::NetConnectNotAllowedError.new(request_signature)
63
+ end
64
+
65
+ WebMock::CallbackRegistry.invoke_callbacks({:lib => :manticore, :real_request => real_request}, request_signature, webmock_response)
66
+ manticore_response
67
+ end
68
+
69
+ def registered_response_for(request_signature)
70
+ WebMock::StubRegistry.instance.response_for_request(request_signature)
71
+ end
72
+
73
+ def real_request_allowed?(uri)
74
+ WebMock.net_connect_allowed?(uri)
75
+ end
76
+
77
+ def generate_webmock_request_signature(request)
78
+ method = request.method.downcase
79
+ uri = request.uri.to_s
80
+ body = read_body(request)
81
+ headers = split_array_values(request.headers)
82
+
83
+ WebMock::RequestSignature.new(method, uri, {:body => body, :headers => headers})
84
+ end
85
+
86
+ def read_body(request)
87
+ if request.respond_to?(:entity) && !request.entity.nil?
88
+ Manticore::EntityConverter.new.read_entity(request.entity)
89
+ end
90
+ end
91
+
92
+ def split_array_values(headers = [])
93
+ headers.each_with_object({}) do |(k, v), h|
94
+ h[k] = case v
95
+ when /,/ then v.split(',').map(&:strip)
96
+ else v
97
+ end
98
+ end
99
+ end
100
+
101
+ def generate_manticore_response(webmock_response)
102
+ raise Manticore::ConnectTimeout if webmock_response.should_timeout
103
+
104
+ Manticore::StubbedResponse.stub(
105
+ :code => webmock_response.status[0],
106
+ :body => webmock_response.body,
107
+ :headers => webmock_response.headers,
108
+ :cookies => {}
109
+ )
110
+ end
111
+
112
+ def generate_webmock_response(manticore_response)
113
+ webmock_response = WebMock::Response.new
114
+ webmock_response.status = [manticore_response.code, manticore_response.message]
115
+ webmock_response.body = manticore_response.body
116
+ webmock_response.headers = manticore_response.headers
117
+ webmock_response
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
@@ -272,10 +272,9 @@ module WebMock
272
272
  method = request.method.downcase.to_sym
273
273
 
274
274
  headers = Hash[*request.to_hash.map {|k,v| [k, v]}.inject([]) {|r,x| r + x}]
275
-
275
+ validate_headers(headers)
276
276
  headers.reject! {|k,v| k =~ /[Aa]uthorization/ && v.first =~ /^Basic / } #we added it to url userinfo
277
277
 
278
-
279
278
  if request.body_stream
280
279
  body = request.body_stream.read
281
280
  request.body_stream = nil
@@ -290,6 +289,21 @@ module WebMock
290
289
  WebMock::RequestSignature.new(method, uri, :body => request.body, :headers => headers)
291
290
  end
292
291
 
292
+ def self.validate_headers(headers)
293
+ # If you make a request with headers that are symbols Net::HTTP raises a NoMethodError
294
+ #
295
+ # WebMock normalizes headers when creating a RequestSignature,
296
+ # and will update all headers from symbols to strings.
297
+ #
298
+ # This could create a false positive in a test suite with WebMock.
299
+ #
300
+ # So before this point, WebMock raises an ArgumentError if any of the headers are symbols
301
+ # instead of the cryptic NoMethodError "undefined method `split' ...` from Net::HTTP
302
+ header_as_symbol = headers.keys.find {|header| header.is_a? Symbol}
303
+ if header_as_symbol
304
+ raise ArgumentError.new("Net:HTTP does not accept headers as symbols")
305
+ end
306
+ end
293
307
 
294
308
  def self.check_right_http_connection
295
309
  @was_right_http_connection_loaded = defined?(RightHttpConnection)
@@ -0,0 +1,63 @@
1
+ require "hashdiff"
2
+ require "json"
3
+
4
+ module WebMock
5
+ class RequestBodyDiff
6
+
7
+ def initialize(request_signature, request_stub)
8
+ @request_signature = request_signature
9
+ @request_stub = request_stub
10
+ end
11
+
12
+ def body_diff
13
+ return {} unless request_signature_diffable? && request_stub_diffable?
14
+
15
+ HashDiff.diff(request_signature_body_hash, request_stub_body_hash)
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :request_signature, :request_stub
21
+
22
+ def request_signature_diffable?
23
+ request_signature.json_headers? && request_signature_parseable_json?
24
+ end
25
+
26
+ def request_stub_diffable?
27
+ request_stub_body.is_a?(Hash) || request_stub_parseable_json?
28
+ end
29
+
30
+ def request_signature_body_hash
31
+ JSON.parse(request_signature.body)
32
+ end
33
+
34
+ def request_stub_body_hash
35
+ return request_stub_body if request_stub_body.is_a?(Hash)
36
+
37
+ JSON.parse(request_stub_body)
38
+ end
39
+
40
+ def request_stub_body
41
+ request_stub.request_pattern &&
42
+ request_stub.request_pattern.body_pattern &&
43
+ request_stub.request_pattern.body_pattern.pattern
44
+ end
45
+
46
+ def request_signature_parseable_json?
47
+ parseable_json?(request_signature.body)
48
+ end
49
+
50
+ def request_stub_parseable_json?
51
+ parseable_json?(request_stub_body)
52
+ end
53
+
54
+ def parseable_json?(body_pattern)
55
+ return false unless body_pattern.is_a?(String)
56
+
57
+ JSON.parse(body_pattern)
58
+ true
59
+ rescue JSON::ParserError
60
+ false
61
+ end
62
+ end
63
+ end