webmock 0.7.3 → 0.8.0

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.
data/CHANGELOG CHANGED
@@ -1,9 +1,24 @@
1
+ == 0.8.0
2
+
3
+ * Support for HTTPClient (sync and async requests)
4
+ * Support for dynamic responses. Response body and headers can be now declared as lambda.
5
+ (Thanks to Ivan Vega ( @ivanyv ) for suggesting this feature)
6
+ * Support for stubbing and expecting requests with empty body
7
+ * Executing non-stubbed request leads to failed expectation instead of error
8
+
9
+ === Bug fixes
10
+
11
+ * Basic authentication now works correctly
12
+ * Fixed problem where WebMock didn't call a block with the response when block was provided
13
+ * Fixed problem where uris with single slash were not matching uris without path provided
14
+
1
15
  == 0.7.3
2
16
 
3
17
  * Clarified documentation
4
18
  * Fixed some issues with loading of Webmock classes
5
19
  * Test::Unit and RSpec adapters have to be required separately
6
20
 
21
+
7
22
  == 0.7.2
8
23
 
9
24
  * Added support for matching escaped and non escaped URLs
data/README.md CHANGED
@@ -13,6 +13,7 @@ Features
13
13
  * Smart matching of the same headers in different representations.
14
14
  * Support for Test::Unit and RSpec (and can be easily extended to other frameworks)
15
15
  * Support for Net::HTTP and other http libraries based on Net::HTTP (i.e RightHttpConnection, rest-client, HTTParty)
16
+ * Support for HTTPClient library (both sync and async requests)
16
17
  * Easy to extend to other HTTP libraries except Net::HTTP
17
18
 
18
19
  Installation
@@ -47,15 +48,15 @@ You can also use WebMock without RSpec or Test::Unit support:
47
48
 
48
49
  ### Stubbed request based on uri only and with the default response
49
50
 
50
- stub_request(:any, "www.google.com")
51
+ stub_request(:any, "www.example.com")
51
52
 
52
- Net::HTTP.get("www.google.com", "/") # ===> Success
53
+ Net::HTTP.get("www.example.com", "/") # ===> Success
53
54
 
54
55
  ### Stubbing requests based on method, uri, body and headers
55
56
 
56
- stub_request(:post, "www.google.com").with(:body => "abc", :headers => { 'Content-Length' => 3 })
57
+ stub_request(:post, "www.example.com").with(:body => "abc", :headers => { 'Content-Length' => 3 })
57
58
 
58
- uri = URI.parse("http://www.google.com/")
59
+ uri = URI.parse("http://www.example.com/")
59
60
  req = Net::HTTP::Post.new(uri.path)
60
61
  req['Content-Length'] = 3
61
62
  res = Net::HTTP.start(uri.host, uri.port) {|http|
@@ -64,10 +65,10 @@ You can also use WebMock without RSpec or Test::Unit support:
64
65
 
65
66
  ### Matching custom request headers
66
67
 
67
- stub_request(:any, "www.google.com").
68
+ stub_request(:any, "www.example.com").
68
69
  with( :headers=>{ 'Header-Name' => 'Header-Value' } ).to_return(:body => "abc", :status => 200)
69
70
 
70
- uri = URI.parse('http://www.google.com/')
71
+ uri = URI.parse('http://www.example.com/')
71
72
  req = Net::HTTP::Post.new(uri.path)
72
73
  req['Header-Name'] = 'Header-Value'
73
74
  res = Net::HTTP.start(uri.host, uri.port) {|http|
@@ -76,37 +77,48 @@ You can also use WebMock without RSpec or Test::Unit support:
76
77
 
77
78
  ### Stubbing with custom response
78
79
 
79
- stub_request(:any, "www.google.com").to_return(:body => "abc", :status => 200, :headers => { 'Content-Length' => 3 } )
80
+ stub_request(:any, "www.example.com").to_return(:body => "abc", :status => 200, :headers => { 'Content-Length' => 3 } )
80
81
 
81
- Net::HTTP.get("www.google.com", '/') # ===> "abc"
82
+ Net::HTTP.get("www.example.com", '/') # ===> "abc"
82
83
 
83
- ### Custom response with body specified as a path to file
84
+ ### Custom response with body specified as IO object
84
85
 
85
86
  File.open('/tmp/response_body.txt', 'w') { |f| f.puts 'abc' }
86
87
 
87
- stub_request(:any, "www.google.com").to_return(:body => "/tmp/response_body.txt", :status => 200)
88
+ stub_request(:any, "www.example.com").to_return(:body => File.new('/tmp/response_body.txt'), :status => 200)
88
89
 
89
- Net::HTTP.get('www.google.com', '/') # ===> "abc\n"
90
+ Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
91
+
92
+ ### Custom response with dynamically evaluated response
93
+
94
+ stub_request(:any, 'www.example.net').
95
+ to_return(:body => lambda { |request| request.body })
96
+
97
+ RestClient.post('www.example.net', 'abc') # ===> "abc\n"
90
98
 
91
99
  ### Request with basic authentication
92
100
 
93
- stub_request(:any, "john:smith@www.google.com")
94
-
95
- Net::HTTP.get(URI.parse('http://john:smith@www.google.com')) # ===> Success
101
+ stub_request(:get, "user:pass@www.example.com")
102
+
103
+ Net::HTTP.start('www.example.com') {|http|
104
+ req = Net::HTTP::Get.new('/')
105
+ req.basic_auth 'user', 'pass'
106
+ http.request(req)
107
+ } # ===> Success
96
108
 
97
109
  ### Matching uris using regular expressions
98
110
 
99
- stub_request(:any, /.*google.*/)
111
+ stub_request(:any, /.*example.*/)
100
112
 
101
- Net::HTTP.get('www.google.com', '/') # ===> Success
113
+ Net::HTTP.get('www.example.com', '/') # ===> Success
102
114
 
103
115
  ### Real requests to network can be allowed or disabled
104
116
 
105
117
  WebMock.allow_net_connect!
106
118
 
107
- stub_request(:any, "www.google.com").to_return(:body => "abc")
119
+ stub_request(:any, "www.example.com").to_return(:body => "abc")
108
120
 
109
- Net::HTTP.get('www.google.com', '/') # ===> "abc"
121
+ Net::HTTP.get('www.example.com', '/') # ===> "abc"
110
122
 
111
123
  Net::HTTP.get('www.something.com', '/') # ===> /.+Something.+/
112
124
 
@@ -120,16 +132,16 @@ You can also use WebMock without RSpec or Test::Unit support:
120
132
  ### Setting expectations in Test::Unit
121
133
  require 'webmock/test_unit'
122
134
 
123
- stub_request(:any, "www.google.com")
135
+ stub_request(:any, "www.example.com")
124
136
 
125
- uri = URI.parse('http://www.google.com/')
137
+ uri = URI.parse('http://www.example.com/')
126
138
  req = Net::HTTP::Post.new(uri.path)
127
139
  req['Content-Length'] = 3
128
140
  res = Net::HTTP.start(uri.host, uri.port) {|http|
129
141
  http.request(req, 'abc')
130
142
  }
131
143
 
132
- assert_requested :post, "http://www.google.com",
144
+ assert_requested :post, "http://www.example.com",
133
145
  :headers => {'Content-Length' => 3}, :body => "abc", :times => 1 # ===> Success
134
146
 
135
147
  assert_not_requested :get, "http://www.something.com" # ===> Success
@@ -138,9 +150,9 @@ You can also use WebMock without RSpec or Test::Unit support:
138
150
 
139
151
  WebMock.allow_net_connect!
140
152
 
141
- Net::HTTP.get('www.google.com', '/') # ===> Success
153
+ Net::HTTP.get('www.example.com', '/') # ===> Success
142
154
 
143
- assert_requested :get, "http://www.google.com" # ===> Success
155
+ assert_requested :get, "http://www.example.com" # ===> Success
144
156
 
145
157
 
146
158
  ### Setting expectations in RSpec
@@ -148,13 +160,13 @@ You can also use WebMock without RSpec or Test::Unit support:
148
160
 
149
161
  require 'webmock/rspec'
150
162
 
151
- WebMock.should have_requested(:get, "www.google.com").with(:body => "abc", :headers => {'Content-Length' => 3}).twice
163
+ WebMock.should have_requested(:get, "www.example.com").with(:body => "abc", :headers => {'Content-Length' => 3}).twice
152
164
 
153
165
  WebMock.should_not have_requested(:get, "www.something.com")
154
166
 
155
167
  ### Different way of setting expectations in RSpec
156
168
 
157
- request(:post, "www.google.com").with(:body => "abc", :headers => {'Content-Length' => 3}).should have_been_made.once
169
+ request(:post, "www.example.com").with(:body => "abc", :headers => {'Content-Length' => 3}).should have_been_made.once
158
170
 
159
171
  request(:post, "www.something.com").should have_been_made.times(3)
160
172
 
@@ -165,34 +177,34 @@ You can also use WebMock without RSpec or Test::Unit support:
165
177
 
166
178
  If you want to reset all current stubs and history of requests use `WebMock.reset_webmock`
167
179
 
168
- stub_request(:any, "www.google.com")
180
+ stub_request(:any, "www.example.com")
169
181
 
170
- Net::HTTP.get('www.google.com', '/') # ===> Success
182
+ Net::HTTP.get('www.example.com', '/') # ===> Success
171
183
 
172
184
  reset_webmock
173
185
 
174
- Net::HTTP.get('www.google.com', '/') # ===> Failure
186
+ Net::HTTP.get('www.example.com', '/') # ===> Failure
175
187
 
176
- assert_not_requested :get, "www.google.com" # ===> Success
188
+ assert_not_requested :get, "www.example.com" # ===> Success
177
189
 
178
190
 
179
191
  ## Matching requests
180
192
 
181
193
  An executed request matches stubbed request if it passes following criteria:
182
194
 
183
- Request URI matches stubbed request URI string or Regexp pattern<br/>
195
+ When request URI matches stubbed request URI string or Regexp pattern<br/>
184
196
  And request method is the same as stubbed request method or stubbed request method is :any<br/>
185
- And request body is the same as stubbed request body or stubbed request body is not set (is nil)<br/>
186
- And request headers match stubbed request headers, or stubbed request headers match a subset of request headers, or stubbed request headers are not set
197
+ And request body is the same as stubbed request body or stubbed request body is not specified<br/>
198
+ And request headers match stubbed request headers, or stubbed request headers match a subset of request headers, or stubbed request headers are not specified
187
199
 
188
200
  ## Precedence of stubs
189
201
 
190
202
  Always the last declared stub matching the request will be applied i.e:
191
203
 
192
- stub_request(:get, "www.google.com").to_return(:body => "abc")
193
- stub_request(:get, "www.google.com").to_return(:body => "def")
204
+ stub_request(:get, "www.example.com").to_return(:body => "abc")
205
+ stub_request(:get, "www.example.com").to_return(:body => "def")
194
206
 
195
- Net::HTTP.get('www.google.com', '/') # ====> "def"
207
+ Net::HTTP.get('www.example.com', '/') # ====> "def"
196
208
 
197
209
  ## Matching URIs
198
210
 
@@ -200,49 +212,49 @@ WebMock will match all different representations of the same URI.
200
212
 
201
213
  I.e all the following representations of the URI are equal:
202
214
 
203
- "www.google.com"
204
- "www.google.com/"
205
- "www.google.com:80"
206
- "www.google.com:80/"
207
- "http://www.google.com"
208
- "http://www.google.com/"
209
- "http://www.google.com:80"
210
- "http://www.google.com:80/"
215
+ "www.example.com"
216
+ "www.example.com/"
217
+ "www.example.com:80"
218
+ "www.example.com:80/"
219
+ "http://www.example.com"
220
+ "http://www.example.com/"
221
+ "http://www.example.com:80"
222
+ "http://www.example.com:80/"
211
223
 
212
224
  The following URIs with basic authentication are also equal for WebMock
213
225
 
214
- "a b:pass@www.google.com"
215
- "a b:pass@www.google.com/"
216
- "a b:pass@www.google.com:80"
217
- "a b:pass@www.google.com:80/"
218
- "http://a b:pass@www.google.com"
219
- "http://a b:pass@www.google.com/"
220
- "http://a b:pass@www.google.com:80"
221
- "http://a b:pass@www.google.com:80/"
222
- "a%20b:pass@www.google.com"
223
- "a%20b:pass@www.google.com/"
224
- "a%20b:pass@www.google.com:80"
225
- "a%20b:pass@www.google.com:80/"
226
- "http://a%20b:pass@www.google.com"
227
- "http://a%20b:pass@www.google.com/"
228
- "http://a%20b:pass@www.google.com:80"
229
- "http://a%20b:pass@www.google.com:80/"
226
+ "a b:pass@www.example.com"
227
+ "a b:pass@www.example.com/"
228
+ "a b:pass@www.example.com:80"
229
+ "a b:pass@www.example.com:80/"
230
+ "http://a b:pass@www.example.com"
231
+ "http://a b:pass@www.example.com/"
232
+ "http://a b:pass@www.example.com:80"
233
+ "http://a b:pass@www.example.com:80/"
234
+ "a%20b:pass@www.example.com"
235
+ "a%20b:pass@www.example.com/"
236
+ "a%20b:pass@www.example.com:80"
237
+ "a%20b:pass@www.example.com:80/"
238
+ "http://a%20b:pass@www.example.com"
239
+ "http://a%20b:pass@www.example.com/"
240
+ "http://a%20b:pass@www.example.com:80"
241
+ "http://a%20b:pass@www.example.com:80/"
230
242
 
231
243
  or these
232
244
 
233
- "www.google.com/big image.jpg/?a=big image&b=c"
234
- "www.google.com/big%20image.jpg/?a=big%20image&b=c"
235
- "www.google.com:80/big image.jpg/?a=big image&b=c"
236
- "www.google.com:80/big%20image.jpg/?a=big%20image&b=c"
237
- "http://www.google.com/big image.jpg/?a=big image&b=c"
238
- "http://www.google.com/big%20image.jpg/?a=big%20image&b=c"
239
- "http://www.google.com:80/big image.jpg/?a=big image&b=c"
240
- "http://www.google.com:80/big%20image.jpg/?a=big%20image&b=c"
245
+ "www.example.com/my path/?a=my param&b=c"
246
+ "www.example.com/my%20path/?a=my%20param&b=c"
247
+ "www.example.com:80/my path/?a=my param&b=c"
248
+ "www.example.com:80/my%20path/?a=my%20param&b=c"
249
+ "http://www.example.com/my path/?a=my param&b=c"
250
+ "http://www.example.com/my%20path/?a=my%20param&b=c"
251
+ "http://www.example.com:80/my path/?a=my param&b=c"
252
+ "http://www.example.com:80/my%20path/?a=my%20param&b=c"
241
253
 
242
254
 
243
255
  If you provide Regexp to match URI, WebMock will try to match it against every valid form of the same url.
244
256
 
245
- I.e `/.*big image.*/` will match `www.google.com/big%20image.jpg` because it is equivalent of `www.google.com/big image.jpg`
257
+ I.e `/.*my param.*/` will match `www.example.com/my%20path` because it is equivalent of `www.example.com/my path`
246
258
 
247
259
 
248
260
  ## Matching headers
data/Rakefile CHANGED
@@ -12,6 +12,7 @@ begin
12
12
  gem.authors = ["Bartosz Blimke"]
13
13
  gem.add_dependency "addressable", ">= 2.1.1"
14
14
  gem.add_development_dependency "rspec", ">= 1.2.9"
15
+ gem.add_development_dependency "httpclient", ">= 2.1.5.2"
15
16
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
17
  end
17
18
  Jeweler::GemcutterTasks.new
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.3
1
+ 0.8.0
data/lib/webmock.rb CHANGED
@@ -3,6 +3,7 @@ require 'singleton'
3
3
  require 'addressable/uri'
4
4
 
5
5
  require 'webmock/http_lib_adapters/net_http'
6
+ require 'webmock/http_lib_adapters/httpclient'
6
7
 
7
8
  require 'webmock/errors'
8
9
 
@@ -10,6 +11,7 @@ require 'webmock/util/uri'
10
11
  require 'webmock/util/headers'
11
12
  require 'webmock/util/hash_counter'
12
13
 
14
+ require 'webmock/request'
13
15
  require 'webmock/request_profile'
14
16
  require 'webmock/request_signature'
15
17
  require 'webmock/request_stub'
@@ -17,10 +17,7 @@ module WebMock
17
17
  end
18
18
 
19
19
  def with(options)
20
- @request_execution_verifier.request_profile.body =
21
- options[:body] if options.has_key?(:body)
22
- @request_execution_verifier.request_profile.headers =
23
- options[:headers] if options.has_key?(:headers)
20
+ @request_execution_verifier.request_profile.with(options)
24
21
  self
25
22
  end
26
23
 
@@ -0,0 +1,96 @@
1
+ if defined?(HTTPClient)
2
+
3
+ class HTTPClient
4
+
5
+ def do_get_block_with_webmock(req, proxy, conn, &block)
6
+ do_get_with_webmock(req, proxy, conn, false, &block)
7
+ end
8
+
9
+ def do_get_stream_with_webmock(req, proxy, conn, &block)
10
+ do_get_with_webmock(req, proxy, conn, true, &block)
11
+ end
12
+
13
+ def do_get_with_webmock(req, proxy, conn, stream = false, &block)
14
+ request_signature = build_request_signature(req)
15
+
16
+ WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
17
+
18
+ if WebMock.registered_request?(request_signature)
19
+ webmock_response = WebMock.response_for_request(request_signature)
20
+ response = build_httpclient_response(webmock_response, stream, &block)
21
+ conn.push(response)
22
+ elsif WebMock.net_connect_allowed?
23
+ if stream
24
+ do_get_stream_without_webmock(req, proxy, conn, &block)
25
+ else
26
+ do_get_block_without_webmock(req, proxy, conn, &block)
27
+ end
28
+ else
29
+ message = "Real HTTP connections are disabled. Unregistered request: #{request_signature}"
30
+ assertion_failure(message)
31
+ end
32
+ end
33
+
34
+ def do_request_async_with_webmock(method, uri, query, body, extheader)
35
+ req = create_request(method, uri, query, body, extheader)
36
+ request_signature = build_request_signature(req)
37
+
38
+ if WebMock.registered_request?(request_signature) || WebMock.net_connect_allowed?
39
+ do_request_async_without_webmock(method, uri, query, body, extheader)
40
+ else
41
+ message = "Real HTTP connections are disabled. Unregistered request: #{request_signature}"
42
+ assertion_failure(message)
43
+ end
44
+ end
45
+
46
+ alias_method :do_get_block_without_webmock, :do_get_block
47
+ alias_method :do_get_block, :do_get_block_with_webmock
48
+
49
+ alias_method :do_get_stream_without_webmock, :do_get_stream
50
+ alias_method :do_get_stream, :do_get_stream_with_webmock
51
+
52
+ alias_method :do_request_async_without_webmock, :do_request_async
53
+ alias_method :do_request_async, :do_request_async_with_webmock
54
+
55
+ def build_httpclient_response(webmock_response, stream = false, &block)
56
+ body = stream ? StringIO.new(webmock_response.body) : webmock_response.body
57
+ response = HTTP::Message.new_response(body)
58
+ response.header.init_response(webmock_response.status)
59
+
60
+ webmock_response.headers.to_a.each { |name, value| response.header.set(name, value) }
61
+
62
+ webmock_response.raise_error_if_any
63
+
64
+ block.call(nil, body) if block
65
+
66
+ response
67
+ end
68
+ end
69
+
70
+ def build_request_signature(req)
71
+ uri = Addressable::URI.heuristic_parse(req.header.request_uri.to_s)
72
+ uri.query_values = req.header.request_query if req.header.request_query
73
+ uri.port = req.header.request_uri.port
74
+ uri = uri.omit(:userinfo)
75
+
76
+ auth = www_auth.basic_auth
77
+ auth.challenge(req.header.request_uri, nil)
78
+
79
+ headers = Hash[req.header.all]
80
+
81
+ if (auth_cred = auth.get(req)) && auth.scheme == 'Basic'
82
+ userinfo = WebMock::Util::Headers.decode_userinfo_from_header(auth_cred)
83
+ userinfo = WebMock::Util::URI.encode_unsafe_chars_in_userinfo(userinfo)
84
+ headers.reject! {|k,v| k =~ /[Aa]uthorization/ && v =~ /^Basic / } #we added it to url userinfo
85
+ uri.userinfo = userinfo
86
+ end
87
+
88
+ request_signature = WebMock::RequestSignature.new(
89
+ req.header.request_method.downcase.to_sym,
90
+ uri.to_s,
91
+ :body => req.body.content,
92
+ :headers => headers
93
+ )
94
+ end
95
+
96
+ end
@@ -35,11 +35,7 @@ module Net #:nodoc: all
35
35
  when Socket, OpenSSL::SSL::SSLSocket, IO
36
36
  io
37
37
  when String
38
- if !io.include?("\0") && File.exists?(io) && !File.directory?(io)
39
- File.open(io, "r")
40
- else
41
- StringIO.new(io)
42
- end
38
+ StringIO.new(io)
43
39
  end
44
40
  raise "Unable to create local socket" unless @io
45
41
  end
@@ -74,8 +70,9 @@ module Net #:nodoc: all
74
70
 
75
71
  headers = Hash[*request.to_hash.map {|k,v| [k, v.flatten]}.flatten]
76
72
  headers.reject! {|k,v| k =~ /[Aa]ccept/ && v = '*/*'} #removing header added by Net::HTTP
73
+ headers.reject! {|k,v| k =~ /[Aa]uthorization/ && v =~ /^Basic / } #we added it to url userinfo
77
74
 
78
- request_signature = WebMock::RequestSignature.new(method, uri, body, headers)
75
+ request_signature = WebMock::RequestSignature.new(method, uri, :body => body, :headers => headers)
79
76
 
80
77
  WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
81
78
 
@@ -88,7 +85,7 @@ module Net #:nodoc: all
88
85
  request_without_webmock(request, body, &block)
89
86
  else
90
87
  message = "Real HTTP connections are disabled. Unregistered request: #{request_signature}"
91
- raise WebMock::NetConnectNotAllowedError, message
88
+ assertion_failure(message)
92
89
  end
93
90
  end
94
91
  alias_method :request_without_webmock, :request