webmock 1.17.4 → 1.18.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +27 -0
- data/README.md +29 -1
- data/lib/webmock.rb +1 -0
- data/lib/webmock/http_lib_adapters/curb_adapter.rb +4 -0
- data/lib/webmock/http_lib_adapters/http_gem/client.rb +14 -0
- data/lib/webmock/http_lib_adapters/http_gem/request.rb +10 -0
- data/lib/webmock/http_lib_adapters/http_gem/response.rb +21 -0
- data/lib/webmock/http_lib_adapters/http_gem/streamer.rb +13 -0
- data/lib/webmock/http_lib_adapters/http_gem/webmock.rb +62 -0
- data/lib/webmock/http_lib_adapters/http_gem_adapter.rb +19 -151
- data/lib/webmock/minitest.rb +8 -2
- data/lib/webmock/rack_response.rb +1 -1
- data/lib/webmock/request_pattern.rb +32 -1
- data/lib/webmock/version.rb +1 -1
- data/spec/acceptance/curb/curb_spec.rb +9 -0
- data/spec/acceptance/http_gem/http_gem_spec.rb +18 -22
- data/spec/acceptance/http_gem/http_gem_spec_helper.rb +20 -29
- data/spec/support/my_rack_app.rb +3 -1
- data/spec/unit/rack_response_spec.rb +10 -0
- data/spec/unit/request_pattern_spec.rb +66 -0
- data/webmock.gemspec +1 -1
- metadata +14 -9
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,32 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 1.18.0
|
4
|
+
|
5
|
+
* Updated dependency on Addressable to versions >= 2.3.6
|
6
|
+
|
7
|
+
* Added support for matching uris using RFC 6570 (URI Templates)
|
8
|
+
|
9
|
+
uri_template = Addressable::Template.new "www.example.com/{id}/"
|
10
|
+
stub_request(:any, uri_template)
|
11
|
+
|
12
|
+
Thanks to [Max Lincoln](https://github.com/maxlinc)
|
13
|
+
|
14
|
+
* Fixed content length calculation for Rack responses with UTF8 body
|
15
|
+
|
16
|
+
Thanks to [Oleg Gritsenko](https://github.com/Claster)
|
17
|
+
|
18
|
+
* Add missing Curl::Easy aliases
|
19
|
+
|
20
|
+
Thanks to [Hwan-Joon Choi](https://github.com/hc5duke)
|
21
|
+
|
22
|
+
* HTTP Gem >= 0.6.0 compatibility
|
23
|
+
|
24
|
+
Thanks to [Aleksey V. Zapparov](https://github.com/ixti)
|
25
|
+
|
26
|
+
* Minitest 4 and 5 compatibility.
|
27
|
+
|
28
|
+
Thanks to [SHIBATA Hiroshi](https://github.com/hsbt)
|
29
|
+
|
3
30
|
## 1.17.4
|
4
31
|
|
5
32
|
* Update matchers for RSpec 3's matcher protocol
|
data/README.md
CHANGED
@@ -212,6 +212,24 @@ stub_request(:any, /.*example.*/)
|
|
212
212
|
Net::HTTP.get('www.example.com', '/') # ===> Success
|
213
213
|
```
|
214
214
|
|
215
|
+
### Matching uris using RFC 6570 - Basic Example
|
216
|
+
|
217
|
+
```ruby
|
218
|
+
uri_template = Addressable::Template.new "www.example.com/{id}/"
|
219
|
+
stub_request(:any, uri_template)
|
220
|
+
|
221
|
+
Net::HTTP.get('www.example.com', '/webmock/') # ===> Success
|
222
|
+
```
|
223
|
+
|
224
|
+
### Matching uris using RFC 6570 - Advanced Example
|
225
|
+
|
226
|
+
```ruby
|
227
|
+
uri_template = Addressable::Template.new "www.example.com/thing/{id}.json{?x,y,z}{&other*}"
|
228
|
+
stub_request(:any, uri_template)
|
229
|
+
|
230
|
+
Net::HTTP.get('www.example.com', '/thing/5.json?x=1&y=2&z=3&anyParam=4') # ===> Success
|
231
|
+
```
|
232
|
+
|
215
233
|
### Matching query params using hash
|
216
234
|
|
217
235
|
```ruby
|
@@ -596,7 +614,7 @@ WebMock.enable!(:except => [:patron]) #enable WebMock for all libs except Pat
|
|
596
614
|
|
597
615
|
An executed request matches stubbed request if it passes following criteria:
|
598
616
|
|
599
|
-
When request URI matches stubbed request URI string or
|
617
|
+
When request URI matches stubbed request URI string, Regexp pattern or RFC 6570 URI Template<br/>
|
600
618
|
And request method is the same as stubbed request method or stubbed request method is :any<br/>
|
601
619
|
And request body is the same as stubbed request body or stubbed request body is not specified<br/>
|
602
620
|
And request headers match stubbed request headers, or stubbed request headers match a subset of request headers, or stubbed request headers are not specified<br/>
|
@@ -668,6 +686,12 @@ If you provide Regexp to match URI, WebMock will try to match it against every v
|
|
668
686
|
|
669
687
|
I.e `/.*my param.*/` will match `www.example.com/my%20path` because it is equivalent of `www.example.com/my path`
|
670
688
|
|
689
|
+
## Matching with URI Templates
|
690
|
+
|
691
|
+
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).
|
692
|
+
|
693
|
+
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.
|
694
|
+
|
671
695
|
## Matching headers
|
672
696
|
|
673
697
|
WebMock will match request headers against stubbed request headers in the following situations:
|
@@ -882,6 +906,10 @@ People who submitted patches and new features or suggested improvements. Many th
|
|
882
906
|
* Bo Jeanes
|
883
907
|
* Matthew Conway
|
884
908
|
* Rob Olson
|
909
|
+
* Max Lincoln
|
910
|
+
* Oleg Gritsenko
|
911
|
+
* Hwan-Joon Choi
|
912
|
+
* SHIBATA Hiroshi
|
885
913
|
|
886
914
|
For a full list of contributors you can visit the
|
887
915
|
[contributors](https://github.com/bblimke/webmock/contributors) page.
|
data/lib/webmock.rb
CHANGED
@@ -200,12 +200,14 @@ if defined?(Curl)
|
|
200
200
|
@put_data = data if data
|
201
201
|
super
|
202
202
|
end
|
203
|
+
alias put http_put
|
203
204
|
|
204
205
|
def http_post *data
|
205
206
|
@webmock_method = :post
|
206
207
|
@post_body = data.join('&') if data && !data.empty?
|
207
208
|
super
|
208
209
|
end
|
210
|
+
alias post http_post
|
209
211
|
|
210
212
|
def perform
|
211
213
|
@webmock_method ||= :get
|
@@ -236,6 +238,7 @@ if defined?(Curl)
|
|
236
238
|
def body_str
|
237
239
|
@body_str || super
|
238
240
|
end
|
241
|
+
alias body body_str
|
239
242
|
|
240
243
|
def response_code
|
241
244
|
@response_code || super
|
@@ -244,6 +247,7 @@ if defined?(Curl)
|
|
244
247
|
def header_str
|
245
248
|
@header_str || super
|
246
249
|
end
|
250
|
+
alias head header_str
|
247
251
|
|
248
252
|
def last_effective_url
|
249
253
|
@last_effective_url || super
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module HTTP
|
2
|
+
class Client
|
3
|
+
alias_method :__perform__, :perform
|
4
|
+
|
5
|
+
def perform(request, options)
|
6
|
+
return __perform__(request, options) unless webmock_enabled?
|
7
|
+
WebMockPerform.new(request) { __perform__(request, options) }.exec
|
8
|
+
end
|
9
|
+
|
10
|
+
def webmock_enabled?
|
11
|
+
::WebMock::HttpLibAdapters::HttpGemAdapter.enabled?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module HTTP
|
2
|
+
class Response
|
3
|
+
def to_webmock
|
4
|
+
webmock_response = ::WebMock::Response.new
|
5
|
+
|
6
|
+
webmock_response.status = [status, reason]
|
7
|
+
webmock_response.body = body.to_s
|
8
|
+
webmock_response.headers = headers.to_h
|
9
|
+
|
10
|
+
webmock_response
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.from_webmock(webmock_response)
|
14
|
+
status = webmock_response.status.first
|
15
|
+
headers = webmock_response.headers || {}
|
16
|
+
body = Body.new Streamer.new webmock_response.body
|
17
|
+
|
18
|
+
new(status, "1.1", headers, body)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module HTTP
|
2
|
+
class WebMockPerform
|
3
|
+
def initialize(request, &perform)
|
4
|
+
@request = request
|
5
|
+
@perform = perform
|
6
|
+
end
|
7
|
+
|
8
|
+
def exec
|
9
|
+
replay || perform || halt
|
10
|
+
end
|
11
|
+
|
12
|
+
def request_signature
|
13
|
+
unless @request_signature
|
14
|
+
@request_signature = @request.webmock_signature
|
15
|
+
register_request(@request_signature)
|
16
|
+
end
|
17
|
+
|
18
|
+
@request_signature
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def response_for_request(signature)
|
24
|
+
::WebMock::StubRegistry.instance.response_for_request(signature)
|
25
|
+
end
|
26
|
+
|
27
|
+
def register_request(signature)
|
28
|
+
::WebMock::RequestRegistry.instance.requested_signatures.put(signature)
|
29
|
+
end
|
30
|
+
|
31
|
+
def replay
|
32
|
+
webmock_response = response_for_request request_signature
|
33
|
+
|
34
|
+
return unless webmock_response
|
35
|
+
|
36
|
+
raise Errno::ETIMEDOUT if webmock_response.should_timeout
|
37
|
+
webmock_response.raise_error_if_any
|
38
|
+
|
39
|
+
invoke_callbacks(webmock_response, :real_request => false)
|
40
|
+
::HTTP::Response.from_webmock webmock_response
|
41
|
+
end
|
42
|
+
|
43
|
+
def perform
|
44
|
+
return unless ::WebMock.net_connect_allowed?(request_signature.uri)
|
45
|
+
response = @perform.call
|
46
|
+
invoke_callbacks(response.to_webmock, :real_request => true)
|
47
|
+
response
|
48
|
+
end
|
49
|
+
|
50
|
+
def halt
|
51
|
+
raise ::WebMock::NetConnectNotAllowedError.new request_signature
|
52
|
+
end
|
53
|
+
|
54
|
+
def invoke_callbacks(webmock_response, options = {})
|
55
|
+
::WebMock::CallbackRegistry.invoke_callbacks(
|
56
|
+
options.merge({ :lib => :http_gem }),
|
57
|
+
request_signature,
|
58
|
+
webmock_response
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -1,170 +1,38 @@
|
|
1
1
|
begin
|
2
2
|
require "http"
|
3
|
+
__http_gem_found__ = true
|
3
4
|
rescue LoadError
|
4
|
-
|
5
|
+
__http_gem_found__ = false
|
5
6
|
end
|
6
7
|
|
8
|
+
if __http_gem_found__
|
9
|
+
WebMock::VersionChecker.new("HTTP Gem", HTTP::VERSION, "0.6.0").check_version!
|
7
10
|
|
8
|
-
if defined?(HTTP::Client)
|
9
11
|
module WebMock
|
10
12
|
module HttpLibAdapters
|
11
13
|
class HttpGemAdapter < HttpLibAdapter
|
12
|
-
|
13
14
|
adapter_for :http_gem
|
14
15
|
|
16
|
+
class << self
|
17
|
+
def enable!
|
18
|
+
@enabled = true
|
19
|
+
end
|
15
20
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
21
|
+
def disable!
|
22
|
+
@enabled = false
|
23
|
+
end
|
20
24
|
|
21
|
-
|
22
|
-
|
25
|
+
def enabled?
|
26
|
+
@enabled
|
27
|
+
end
|
23
28
|
end
|
24
|
-
|
25
29
|
end
|
26
30
|
end
|
27
31
|
end
|
28
32
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
::WebMock::RequestSignature.new(method, uri.to_s, {
|
35
|
-
:headers => headers,
|
36
|
-
:body => body
|
37
|
-
})
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
41
|
-
|
42
|
-
|
43
|
-
class Response
|
44
|
-
|
45
|
-
def to_webmock
|
46
|
-
webmock_response = ::WebMock::Response.new
|
47
|
-
|
48
|
-
webmock_response.status = [status, reason]
|
49
|
-
webmock_response.body = body.to_s
|
50
|
-
webmock_response.headers = headers
|
51
|
-
|
52
|
-
webmock_response
|
53
|
-
end
|
54
|
-
|
55
|
-
|
56
|
-
def self.from_webmock(webmock_response)
|
57
|
-
status = webmock_response.status.first
|
58
|
-
headers = webmock_response.headers || {}
|
59
|
-
body = webmock_response.body
|
60
|
-
|
61
|
-
new(status, "1.1", headers, body)
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
class WebMockPerform
|
68
|
-
|
69
|
-
def initialize request, &perform
|
70
|
-
@request = request
|
71
|
-
@perform = perform
|
72
|
-
end
|
73
|
-
|
74
|
-
|
75
|
-
def exec
|
76
|
-
replay || perform || halt
|
77
|
-
end
|
78
|
-
|
79
|
-
|
80
|
-
def request_signature
|
81
|
-
unless @request_signature
|
82
|
-
@request_signature = @request.webmock_signature
|
83
|
-
register_request(@request_signature)
|
84
|
-
end
|
85
|
-
|
86
|
-
@request_signature
|
87
|
-
end
|
88
|
-
|
89
|
-
|
90
|
-
protected
|
91
|
-
|
92
|
-
|
93
|
-
def response_for_request(signature)
|
94
|
-
::WebMock::StubRegistry.instance.response_for_request(signature)
|
95
|
-
end
|
96
|
-
|
97
|
-
|
98
|
-
def register_request(signature)
|
99
|
-
::WebMock::RequestRegistry.instance.requested_signatures.put(signature)
|
100
|
-
end
|
101
|
-
|
102
|
-
|
103
|
-
def replay
|
104
|
-
webmock_response = response_for_request(request_signature)
|
105
|
-
|
106
|
-
return unless webmock_response
|
107
|
-
|
108
|
-
raise Errno::ETIMEDOUT if webmock_response.should_timeout
|
109
|
-
webmock_response.raise_error_if_any
|
110
|
-
|
111
|
-
invoke_callbacks(webmock_response, :real_request => false)
|
112
|
-
::HTTP::Response.from_webmock webmock_response
|
113
|
-
end
|
114
|
-
|
115
|
-
|
116
|
-
def perform
|
117
|
-
return unless ::WebMock.net_connect_allowed?(request_signature.uri)
|
118
|
-
response = @perform.call
|
119
|
-
invoke_callbacks(response.to_webmock, :real_request => true)
|
120
|
-
response
|
121
|
-
end
|
122
|
-
|
123
|
-
|
124
|
-
def halt
|
125
|
-
raise ::WebMock::NetConnectNotAllowedError.new request_signature
|
126
|
-
end
|
127
|
-
|
128
|
-
|
129
|
-
def invoke_callbacks webmock_response, options = {}
|
130
|
-
::WebMock::CallbackRegistry.invoke_callbacks(
|
131
|
-
options.merge({ :lib => :http_gem }),
|
132
|
-
request_signature,
|
133
|
-
webmock_response
|
134
|
-
)
|
135
|
-
end
|
136
|
-
|
137
|
-
end
|
138
|
-
|
139
|
-
|
140
|
-
class Client
|
141
|
-
|
142
|
-
alias :__perform__ :perform
|
143
|
-
|
144
|
-
def perform request, options
|
145
|
-
return __perform__(request, options) unless ::HTTP.webmock_enabled?
|
146
|
-
WebMockPerform.new(request) { __perform__(request, options) }.exec
|
147
|
-
end
|
148
|
-
|
149
|
-
end
|
150
|
-
|
151
|
-
|
152
|
-
class << self
|
153
|
-
|
154
|
-
def enable_webmock!
|
155
|
-
@webmock_enabled = true
|
156
|
-
end
|
157
|
-
|
158
|
-
|
159
|
-
def disable_webmock!
|
160
|
-
@webmock_enabled = false
|
161
|
-
end
|
162
|
-
|
163
|
-
|
164
|
-
def webmock_enabled?
|
165
|
-
@webmock_enabled
|
166
|
-
end
|
167
|
-
|
168
|
-
end
|
169
|
-
end
|
33
|
+
require "webmock/http_lib_adapters/http_gem/client"
|
34
|
+
require "webmock/http_lib_adapters/http_gem/request"
|
35
|
+
require "webmock/http_lib_adapters/http_gem/response"
|
36
|
+
require "webmock/http_lib_adapters/http_gem/streamer"
|
37
|
+
require "webmock/http_lib_adapters/http_gem/webmock"
|
170
38
|
end
|
data/lib/webmock/minitest.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
begin
|
2
2
|
require 'minitest/test'
|
3
|
-
test_class=
|
3
|
+
test_class = Minitest::Test
|
4
4
|
assertions = "assertions"
|
5
5
|
rescue LoadError
|
6
6
|
require "minitest/unit"
|
@@ -30,4 +30,10 @@ test_class.class_eval do
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
|
33
|
+
begin
|
34
|
+
error_class = MiniTest::Assertion
|
35
|
+
rescue NameError
|
36
|
+
error_class = Minitest::Assertion
|
37
|
+
end
|
38
|
+
|
39
|
+
WebMock::AssertionFailure.error_class = error_class
|
@@ -32,7 +32,7 @@ module WebMock
|
|
32
32
|
# CGI variables specified by Rack
|
33
33
|
'REQUEST_METHOD' => request.method.to_s.upcase,
|
34
34
|
'CONTENT_TYPE' => headers.delete('Content-Type'),
|
35
|
-
'CONTENT_LENGTH' => body.
|
35
|
+
'CONTENT_LENGTH' => body.bytesize,
|
36
36
|
'PATH_INFO' => uri.path,
|
37
37
|
'QUERY_STRING' => uri.query || '',
|
38
38
|
'SERVER_NAME' => uri.host,
|
@@ -56,6 +56,8 @@ module WebMock
|
|
56
56
|
def create_uri_pattern(uri)
|
57
57
|
if uri.is_a?(Regexp)
|
58
58
|
URIRegexpPattern.new(uri)
|
59
|
+
elsif uri.is_a?(Addressable::Template)
|
60
|
+
URIAddressablePattern.new(uri)
|
59
61
|
else
|
60
62
|
URIStringPattern.new(uri)
|
61
63
|
end
|
@@ -83,7 +85,12 @@ module WebMock
|
|
83
85
|
include RSpecMatcherDetector
|
84
86
|
|
85
87
|
def initialize(pattern)
|
86
|
-
@pattern =
|
88
|
+
@pattern = case pattern
|
89
|
+
when Addressable::URI, Addressable::Template
|
90
|
+
pattern
|
91
|
+
else
|
92
|
+
WebMock::Util::URI.normalize_uri(pattern)
|
93
|
+
end
|
87
94
|
@query_params = nil
|
88
95
|
end
|
89
96
|
|
@@ -119,6 +126,30 @@ module WebMock
|
|
119
126
|
end
|
120
127
|
end
|
121
128
|
|
129
|
+
class URIAddressablePattern < URIPattern
|
130
|
+
def matches?(uri)
|
131
|
+
if @query_params.nil?
|
132
|
+
# Let Addressable check the whole URI
|
133
|
+
WebMock::Util::URI.variations_of_uri_as_strings(uri).any? { |u| @pattern.match(u) }
|
134
|
+
else
|
135
|
+
# WebMock checks the query, Addressable checks everything else
|
136
|
+
WebMock::Util::URI.variations_of_uri_as_strings(uri.omit(:query)).any? { |u| @pattern.match(u) } &&
|
137
|
+
(@query_params.nil? || @query_params == WebMock::Util::QueryMapper.query_to_values(uri.query))
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def add_query_params(query_params)
|
142
|
+
warn "WebMock warning: ignoring query params in RFC 6570 template and checking them with WebMock"
|
143
|
+
super(query_params)
|
144
|
+
end
|
145
|
+
|
146
|
+
def to_s
|
147
|
+
str = @pattern.pattern.inspect
|
148
|
+
str += " with variables #{@pattern.variables.inspect}" if @pattern.variables
|
149
|
+
str
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
122
153
|
class URIStringPattern < URIPattern
|
123
154
|
def matches?(uri)
|
124
155
|
if @pattern.is_a?(Addressable::URI)
|
data/lib/webmock/version.rb
CHANGED
@@ -331,6 +331,15 @@ unless RUBY_PLATFORM =~ /java/
|
|
331
331
|
c.http(:GET)
|
332
332
|
c.body_str.should == "abc"
|
333
333
|
end
|
334
|
+
|
335
|
+
it "should alias body to body_str" do
|
336
|
+
stub_request(:get, "www.example.com").to_return(:body => "abc")
|
337
|
+
|
338
|
+
c = Curl::Easy.new
|
339
|
+
c.url = "http://www.example.com"
|
340
|
+
c.http(:GET)
|
341
|
+
c.body.should == "abc"
|
342
|
+
end
|
334
343
|
end
|
335
344
|
|
336
345
|
describe "using #http_* methods for requests" do
|
@@ -5,50 +5,46 @@ require "acceptance/webmock_shared"
|
|
5
5
|
require "acceptance/http_gem/http_gem_spec_helper"
|
6
6
|
|
7
7
|
describe "HTTP Gem" do
|
8
|
-
|
9
8
|
include HttpGemSpecHelper
|
10
9
|
|
11
|
-
|
12
10
|
include_examples "with WebMock", :no_status_message
|
13
11
|
|
12
|
+
context "streaming body" do
|
13
|
+
let(:response) { HTTP.get "http://example.com" }
|
14
|
+
before { stub_simple_request "example.com", 302, {}, "abc" }
|
15
|
+
|
16
|
+
it "works as if it was streamed from socket" do
|
17
|
+
expect(response.body.readpartial 1).to eq "a"
|
18
|
+
end
|
14
19
|
|
15
|
-
|
20
|
+
it "fails if body was already streamed" do
|
21
|
+
response.body.to_s
|
22
|
+
expect { response.body.readpartial 1 }.to raise_error
|
23
|
+
end
|
24
|
+
end
|
16
25
|
|
26
|
+
context "without following redirects" do
|
17
27
|
let(:response) { http_request(:get, "http://example.com") }
|
18
28
|
let(:headers) { response.headers }
|
19
29
|
|
20
30
|
it "stops on first request" do
|
21
|
-
stub_simple_request("example.com", 302, "Location" => "www.example.com")
|
31
|
+
stub_simple_request("example.com", 302, "Location" => "http://www.example.com")
|
22
32
|
stub_simple_request("www.example.com")
|
23
33
|
|
24
34
|
expect(headers).to include "Host" => "example.com"
|
25
35
|
end
|
26
|
-
|
27
36
|
end
|
28
37
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
let(:response) { http_request(:get, "http://example.com", :follow => true) }
|
38
|
+
context "following redirects" do
|
39
|
+
let(:options) { { :follow => true } }
|
40
|
+
let(:response) { http_request(:get, "http://example.com", options) }
|
33
41
|
let(:headers) { response.headers }
|
34
42
|
|
35
|
-
|
36
43
|
it "returns response of destination" do
|
37
|
-
stub_simple_request("example.com", 302, "Location" => "www.example.com")
|
44
|
+
stub_simple_request("example.com", 302, "Location" => "http://www.example.com")
|
38
45
|
stub_simple_request("www.example.com")
|
39
46
|
|
40
47
|
expect(headers).to include "Host" => "www.example.com"
|
41
48
|
end
|
42
|
-
|
43
|
-
|
44
|
-
it "works with more than one redirect" do
|
45
|
-
stub_simple_request("example.com", 302, "Location" => "www.example.com")
|
46
|
-
stub_simple_request("www.example.com", 302, "Location" => "blog.example.com")
|
47
|
-
stub_simple_request("blog.example.com")
|
48
|
-
|
49
|
-
expect(headers).to include "Host" => "blog.example.com"
|
50
|
-
end
|
51
|
-
|
52
49
|
end
|
53
|
-
|
54
50
|
end
|
@@ -1,52 +1,43 @@
|
|
1
1
|
require "ostruct"
|
2
2
|
|
3
|
-
|
4
3
|
module HttpGemSpecHelper
|
5
|
-
|
6
|
-
|
7
|
-
response = HTTP.request(method, normalize_uri(uri), options).response
|
4
|
+
def http_request(method, uri, options = {})
|
5
|
+
response = HTTP.request(method, normalize_uri(uri), options)
|
8
6
|
|
9
7
|
OpenStruct.new({
|
10
|
-
:body => response.body,
|
11
|
-
:headers => normalize_headers(response.headers),
|
8
|
+
:body => response.body.to_s,
|
9
|
+
:headers => normalize_headers(response.headers.to_h),
|
12
10
|
:status => response.status.to_s,
|
13
11
|
:message => response.reason
|
14
12
|
})
|
15
13
|
end
|
16
14
|
|
17
|
-
|
18
|
-
def normalize_uri(uri)
|
19
|
-
Addressable::URI.heuristic_parse(uri).normalize.to_s
|
20
|
-
end
|
21
|
-
|
22
|
-
|
23
|
-
def normalize_headers headers
|
24
|
-
WebMock::Util::Headers.normalize_headers(Hash[headers.map { |k, v|
|
25
|
-
[k, v.is_a?(Array) ? v.join(", ") : v]
|
26
|
-
}])
|
27
|
-
end
|
28
|
-
|
29
|
-
|
30
|
-
def stub_simple_request host, status = 200, headers = {}
|
31
|
-
stub_request(:any, host).to_return({
|
32
|
-
:status => status,
|
33
|
-
:headers => headers.merge({ "Host" => host })
|
34
|
-
})
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
15
|
def client_timeout_exception_class
|
39
16
|
Errno::ETIMEDOUT
|
40
17
|
end
|
41
18
|
|
42
|
-
|
43
19
|
def connection_refused_exception_class
|
44
20
|
Errno::ECONNREFUSED
|
45
21
|
end
|
46
22
|
|
47
|
-
|
48
23
|
def http_library
|
49
24
|
:http_gem
|
50
25
|
end
|
51
26
|
|
27
|
+
def normalize_uri(uri)
|
28
|
+
Addressable::URI.heuristic_parse(uri).normalize.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
def normalize_headers(headers)
|
32
|
+
headers = Hash[headers.map { |k, v| [k, Array(v).join(", ")] }]
|
33
|
+
WebMock::Util::Headers.normalize_headers headers
|
34
|
+
end
|
35
|
+
|
36
|
+
def stub_simple_request(host, status = 200, headers = {}, body = nil)
|
37
|
+
stub_request(:any, host).to_return({
|
38
|
+
:status => status,
|
39
|
+
:headers => headers.merge({ "Host" => host }),
|
40
|
+
:body => body
|
41
|
+
})
|
42
|
+
end
|
52
43
|
end
|
data/spec/support/my_rack_app.rb
CHANGED
@@ -24,7 +24,9 @@ class MyRackApp
|
|
24
24
|
when ['GET', '/locked']
|
25
25
|
[200, {}, ["Single threaded response."]]
|
26
26
|
when ['POST', '/greet']
|
27
|
-
name = env["rack.input"].read
|
27
|
+
name = env["rack.input"].read(env["CONTENT_LENGTH"])
|
28
|
+
name = name.force_encoding("UTF-8") if name.respond_to? :force_encoding
|
29
|
+
name = name[/name=([^&]*)/, 1] || "World"
|
28
30
|
[200, {}, ["Good to meet you, #{name}!"]]
|
29
31
|
when ['GET', '/compute']
|
30
32
|
if env['SERVER_PORT'] == 80 && env["SCRIPT_NAME"] == ""
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
require 'spec_helper'
|
2
3
|
|
3
4
|
describe WebMock::RackResponse do
|
@@ -49,6 +50,15 @@ describe WebMock::RackResponse do
|
|
49
50
|
response.body.should include('Good to meet you, Jimmy!')
|
50
51
|
end
|
51
52
|
|
53
|
+
it "should send params with proper content length if params have non-ascii symbols" do
|
54
|
+
request = WebMock::RequestSignature.new(:post, 'www.example.com/greet',
|
55
|
+
:body => 'name=Олег'
|
56
|
+
)
|
57
|
+
|
58
|
+
response = @rack_response.evaluate(request)
|
59
|
+
response.body.should include('Good to meet you, Олег!')
|
60
|
+
end
|
61
|
+
|
52
62
|
describe 'rack error output' do
|
53
63
|
before :each do
|
54
64
|
@original_stderr = $stderr
|
@@ -99,6 +99,16 @@ describe WebMock::RequestPattern do
|
|
99
99
|
should match(WebMock::RequestSignature.new(:get, "www.example.com"))
|
100
100
|
end
|
101
101
|
|
102
|
+
it "should match if uri Addressable::Template pattern matches unescaped form of request uri" do
|
103
|
+
WebMock::RequestPattern.new(:get, Addressable::Template.new("www.example.com/{any_path}")).
|
104
|
+
should match(WebMock::RequestSignature.new(:get, "www.example.com/my%20path"))
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should match if uri Addressable::Template pattern matches request uri" do
|
108
|
+
WebMock::RequestPattern.new(:get, Addressable::Template.new("www.example.com")).
|
109
|
+
should match(WebMock::RequestSignature.new(:get, "www.example.com"))
|
110
|
+
end
|
111
|
+
|
102
112
|
it "should match for uris with same parameters as pattern" do
|
103
113
|
WebMock::RequestPattern.new(:get, "www.example.com?a=1&b=2").
|
104
114
|
should match(WebMock::RequestSignature.new(:get, "www.example.com?a=1&b=2"))
|
@@ -136,6 +146,26 @@ describe WebMock::RequestPattern do
|
|
136
146
|
should match(WebMock::RequestSignature.new(:get, "www.example.com/?a=a b"))
|
137
147
|
end
|
138
148
|
|
149
|
+
it "should match if uri Addressable::Template pattern matches uri without parameter value and request has escaped parameters" do
|
150
|
+
WebMock::RequestPattern.new(:get, Addressable::Template.new("www.example.com/{?a}")).
|
151
|
+
should match(WebMock::RequestSignature.new(:get, "www.example.com/?a=a%20b"))
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should match if uri Addressable::Template pattern matches uri without parameter value and request has unescaped parameters" do
|
155
|
+
WebMock::RequestPattern.new(:get, Addressable::Template.new("www.example.com/{?a}")).
|
156
|
+
should match(WebMock::RequestSignature.new(:get, "www.example.com/?a=a b"))
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should match if uri Addressable::Template pattern matches uri with unescaped parameter value and request has unescaped parameters" do
|
160
|
+
WebMock::RequestPattern.new(:get, Addressable::Template.new("www.example.com/?a=a b")).
|
161
|
+
should match(WebMock::RequestSignature.new(:get, "www.example.com/?a=a b"))
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should match if uri Addressable::Template pattern matches uri with escaped parameter value and request has escaped parameters" do
|
165
|
+
WebMock::RequestPattern.new(:get, Addressable::Template.new("www.example.com/?a=a%20b")).
|
166
|
+
should match(WebMock::RequestSignature.new(:get, "www.example.com/?a=a%20b"))
|
167
|
+
end
|
168
|
+
|
139
169
|
end
|
140
170
|
|
141
171
|
describe "when matching requests on query params" do
|
@@ -176,6 +206,42 @@ describe WebMock::RequestPattern do
|
|
176
206
|
end
|
177
207
|
end
|
178
208
|
|
209
|
+
describe "when uri is described as Addressable::Template" do
|
210
|
+
it "should raise error if query params are specified" do
|
211
|
+
WebMock::RequestPattern.new(:get, Addressable::Template.new("www.example.com"), :query => {"a" => ["b", "c"]}).
|
212
|
+
should match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c"))
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should match request query params if params don't match" do
|
216
|
+
WebMock::RequestPattern.new(:get, Addressable::Template.new("www.example.com"), :query => {"x" => ["b", "c"]}).
|
217
|
+
should_not match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c"))
|
218
|
+
end
|
219
|
+
|
220
|
+
it "should match when query params are declared as HashIncluding matcher matching params" do
|
221
|
+
WebMock::RequestPattern.new(:get, Addressable::Template.new("www.example.com"),
|
222
|
+
:query => WebMock::Matchers::HashIncludingMatcher.new({"a" => ["b", "c"]})).
|
223
|
+
should match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c&b=1"))
|
224
|
+
end
|
225
|
+
|
226
|
+
it "should not match when query params are declared as HashIncluding matcher not matching params" do
|
227
|
+
WebMock::RequestPattern.new(:get, Addressable::Template.new("www.example.com"),
|
228
|
+
:query => WebMock::Matchers::HashIncludingMatcher.new({"x" => ["b", "c"]})).
|
229
|
+
should_not match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c&b=1"))
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should match when query params are declared as RSpec HashIncluding matcher matching params" do
|
233
|
+
WebMock::RequestPattern.new(:get, Addressable::Template.new("www.example.com"),
|
234
|
+
:query => RSpec::Mocks::ArgumentMatchers::HashIncludingMatcher.new({"a" => ["b", "c"]})).
|
235
|
+
should match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c&b=1"))
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should not match when query params are declared as RSpec HashIncluding matcher not matching params" do
|
239
|
+
WebMock::RequestPattern.new(:get, Addressable::Template.new("www.example.com"),
|
240
|
+
:query => RSpec::Mocks::ArgumentMatchers::HashIncludingMatcher.new({"a" => ["b", "d"]})).
|
241
|
+
should_not match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c&b=1"))
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
179
245
|
describe "when uri is described as string" do
|
180
246
|
it "should match when query params are the same as declared in hash" do
|
181
247
|
WebMock::RequestPattern.new(:get, "www.example.com", :query => {"a" => ["b", "c"]}).
|
data/webmock.gemspec
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: webmock
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 95
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 1.
|
8
|
+
- 18
|
9
|
+
- 0
|
10
|
+
version: 1.18.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Bartosz Blimke
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2014-
|
18
|
+
date: 2014-05-13 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -25,12 +25,12 @@ dependencies:
|
|
25
25
|
requirements:
|
26
26
|
- - ">="
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
hash:
|
28
|
+
hash: 15
|
29
29
|
segments:
|
30
30
|
- 2
|
31
|
-
-
|
32
|
-
-
|
33
|
-
version: 2.
|
31
|
+
- 3
|
32
|
+
- 6
|
33
|
+
version: 2.3.6
|
34
34
|
prerelease: false
|
35
35
|
requirement: *id001
|
36
36
|
name: addressable
|
@@ -249,6 +249,11 @@ files:
|
|
249
249
|
- lib/webmock/http_lib_adapters/em_http_request/em_http_request_1_x.rb
|
250
250
|
- lib/webmock/http_lib_adapters/em_http_request_adapter.rb
|
251
251
|
- lib/webmock/http_lib_adapters/excon_adapter.rb
|
252
|
+
- lib/webmock/http_lib_adapters/http_gem/client.rb
|
253
|
+
- lib/webmock/http_lib_adapters/http_gem/request.rb
|
254
|
+
- lib/webmock/http_lib_adapters/http_gem/response.rb
|
255
|
+
- lib/webmock/http_lib_adapters/http_gem/streamer.rb
|
256
|
+
- lib/webmock/http_lib_adapters/http_gem/webmock.rb
|
252
257
|
- lib/webmock/http_lib_adapters/http_gem_adapter.rb
|
253
258
|
- lib/webmock/http_lib_adapters/http_lib_adapter.rb
|
254
259
|
- lib/webmock/http_lib_adapters/http_lib_adapter_registry.rb
|