webmock 0.8.2 → 0.9.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.
@@ -0,0 +1,113 @@
1
+ #Changelog
2
+
3
+ ## 0.9.0
4
+
5
+ * Matching requests against provided block (by Sergio Gil)
6
+
7
+ stub_request(:post, "www.example.com").with { |request| request.body == "abc" }.to_return(:body => "def")
8
+ RestClient.post('www.example.com', 'abc') # ===> "def\n"
9
+ request(:post, "www.example.com").with { |req| req.body == "abc" }.should have_been_made
10
+ #or
11
+ assert_requested(:post, "www.example.com") { |req| req.body == "abc" }
12
+
13
+ * Matching request body against regular expressions
14
+
15
+ stub_request(:post, "www.example.com").with(:body => /^.*world$/).to_return(:body => "abc")
16
+ RestClient.post('www.example.com', 'hello world') # ===> "abc\n"
17
+
18
+ * Matching request headers against regular expressions
19
+
20
+ stub_request(:post, "www.example.com").with(:headers => {"Content-Type" => /image\/.+/}).to_return(:body => "abc")
21
+ RestClient.post('www.example.com', '', {'Content-Type' => 'image/png'}) # ===> "abc\n"
22
+
23
+ * Replaying raw responses recorded with `curl -is`
24
+
25
+ `curl -is www.example.com > /tmp/example_curl_-is_output.txt`
26
+ raw_response_file = File.new("/tmp/example_curl_-is_output.txt")
27
+
28
+ from file
29
+
30
+ stub_request(:get, "www.example.com").to_return(raw_response_file)
31
+
32
+ or string
33
+
34
+ stub_request(:get, "www.example.com").to_return(raw_response_file.read)
35
+
36
+ * Multiple responses for repeated requests
37
+
38
+ stub_request(:get, "www.example.com").to_return({:body => "abc"}, {:body => "def"})
39
+ Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
40
+ Net::HTTP.get('www.example.com', '/') # ===> "def\n"
41
+
42
+ * Multiple responses using chained `to_return()` or `to_raise()` declarations
43
+
44
+ stub_request(:get, "www.example.com").
45
+ to_return({:body => "abc"}).then. #then() just is a syntactic sugar
46
+ to_return({:body => "def"}).then.
47
+ to_raise(MyException)
48
+ Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
49
+ Net::HTTP.get('www.example.com', '/') # ===> "def\n"
50
+ Net::HTTP.get('www.example.com', '/') # ===> MyException raised
51
+
52
+ * Specifying number of times given response should be returned
53
+
54
+ stub_request(:get, "www.example.com").
55
+ to_return({:body => "abc"}).times(2).then.
56
+ to_return({:body => "def"})
57
+
58
+ Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
59
+ Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
60
+ Net::HTTP.get('www.example.com', '/') # ===> "def\n"
61
+
62
+ * Added support for `Net::HTTP::Post#body_stream`
63
+
64
+ This fixes compatibility with new versions of RestClient
65
+
66
+ * WebMock doesn't suppress default request headers added by http clients anymore.
67
+
68
+ i.e. Net::HTTP adds `'Accept'=>'*/*'` to all requests by default
69
+
70
+
71
+
72
+ ## 0.8.2
73
+
74
+ * Fixed issue where WebMock was not closing IO object passed as response body after reading it.
75
+ * Ruby 1.9.2 compat: Use `File#expand_path` for require path because "." is not be included in LOAD_PATH since Ruby 1.9.2
76
+
77
+
78
+ ## 0.8.1
79
+
80
+ * Fixed HTTPClient adapter compatibility with Ruby 1.8.6 (reported by Piotr Usewicz)
81
+ * Net:HTTP adapter now handles request body assigned as Net::HTTP::Post#body attribute (fixed by Mack Earnhardt)
82
+ * Fixed issue where requests were not matching stubs with Accept header set.(reported by Piotr Usewicz)
83
+ * Fixed compatibility with Ruby 1.9.1, 1.9.2 and JRuby 1.3.1 (reported by Diego E. “Flameeyes” Pettenò)
84
+ * Fixed issue with response body declared as IO object and multiple requests (reported by Niels Meersschaert)
85
+ * Fixed "undefined method `assertion_failure'" error (reported by Nick Plante)
86
+
87
+
88
+ ## 0.8.0
89
+
90
+ * Support for HTTPClient (sync and async requests)
91
+ * Support for dynamic responses. Response body and headers can be now declared as lambda.
92
+ (Thanks to Ivan Vega ( @ivanyv ) for suggesting this feature)
93
+ * Support for stubbing and expecting requests with empty body
94
+ * Executing non-stubbed request leads to failed expectation instead of error
95
+
96
+
97
+ ### Bug fixes
98
+
99
+ * Basic authentication now works correctly
100
+ * Fixed problem where WebMock didn't call a block with the response when block was provided
101
+ * Fixed problem where uris with single slash were not matching uris without path provided
102
+
103
+
104
+ ## 0.7.3
105
+
106
+ * Clarified documentation
107
+ * Fixed some issues with loading of Webmock classes
108
+ * Test::Unit and RSpec adapters have to be required separately
109
+
110
+
111
+ ## 0.7.2
112
+
113
+ * Added support for matching escaped and non escaped URLs
data/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  WebMock
2
2
  =======
3
3
 
4
- Library for stubbing HTTP requests and setting expectations on HTTP requests in Ruby.
4
+ Library for stubbing and setting expectations on HTTP requests in Ruby.
5
5
 
6
6
  Features
7
7
  --------
8
8
 
9
- * Stubbing HTTP requests at low Net::HTTP level (no need to change tests when you change HTTP lib interface)
9
+ * Stubbing HTTP requests at low http client lib level (no need to change tests when you change HTTP library)
10
10
  * Setting and verifying expectations on HTTP requests
11
11
  * Matching requests based on method, URI, headers and body
12
12
  * Smart matching of the same URIs in different representations (also encoded and non encoded forms)
@@ -14,7 +14,7 @@ Features
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
16
  * Support for HTTPClient library (both sync and async requests)
17
- * Easy to extend to other HTTP libraries except Net::HTTP
17
+ * Easy to extend to other HTTP libraries
18
18
 
19
19
  Installation
20
20
  ------------
@@ -63,10 +63,21 @@ You can also use WebMock without RSpec or Test::Unit support:
63
63
  http.request(req, "abc")
64
64
  } # ===> Success
65
65
 
66
+ ### Matching request body and headers against regular expressions
67
+
68
+ stub_request(:post, "www.example.com").
69
+ with(:body => /^.*world$/, :headers => {"Content-Type" => /image\/.+/}).to_return(:body => "abc")
70
+
71
+ uri = URI.parse('http://www.example.com/')
72
+ req = Net::HTTP::Post.new(uri.path)
73
+ req['Content-Type'] = 'image/png'
74
+ res = Net::HTTP.start(uri.host, uri.port) {|http|
75
+ http.request(req, 'hello world')
76
+ } # ===> Success
77
+
66
78
  ### Matching custom request headers
67
79
 
68
- stub_request(:any, "www.example.com").
69
- with( :headers=>{ 'Header-Name' => 'Header-Value' } ).to_return(:body => "abc", :status => 200)
80
+ stub_request(:any, "www.example.com").with(:headers=>{ 'Header-Name' => 'Header-Value' })
70
81
 
71
82
  uri = URI.parse('http://www.example.com/')
72
83
  req = Net::HTTP::Post.new(uri.path)
@@ -75,6 +86,27 @@ You can also use WebMock without RSpec or Test::Unit support:
75
86
  http.request(req, 'abc')
76
87
  } # ===> Success
77
88
 
89
+ ### Matching requests against provided block
90
+
91
+ stub_request(:post, "www.example.com").with { |request| request.body == "abc" }
92
+ RestClient.post('www.example.com', 'abc') # ===> Success
93
+
94
+ ### Request with basic authentication
95
+
96
+ stub_request(:get, "user:pass@www.example.com")
97
+
98
+ Net::HTTP.start('www.example.com') {|http|
99
+ req = Net::HTTP::Get.new('/')
100
+ req.basic_auth 'user', 'pass'
101
+ http.request(req)
102
+ } # ===> Success
103
+
104
+ ### Matching uris using regular expressions
105
+
106
+ stub_request(:any, /.*example.*/)
107
+
108
+ Net::HTTP.get('www.example.com', '/') # ===> Success
109
+
78
110
  ### Stubbing with custom response
79
111
 
80
112
  stub_request(:any, "www.example.com").to_return(:body => "abc", :status => 200, :headers => { 'Content-Length' => 3 } )
@@ -88,6 +120,19 @@ You can also use WebMock without RSpec or Test::Unit support:
88
120
  stub_request(:any, "www.example.com").to_return(:body => File.new('/tmp/response_body.txt'), :status => 200)
89
121
 
90
122
  Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
123
+
124
+ ### Replaying raw responses recorded with `curl -is`
125
+
126
+ `curl -is www.example.com > /tmp/example_curl_-is_output.txt`
127
+ raw_response_file = File.new("/tmp/example_curl_-is_output.txt")
128
+
129
+ from file
130
+
131
+ stub_request(:get, "www.example.com").to_return(raw_response_file)
132
+
133
+ or string
134
+
135
+ stub_request(:get, "www.example.com").to_return(raw_response_file.read)
91
136
 
92
137
  ### Custom response with dynamically evaluated response
93
138
 
@@ -96,21 +141,36 @@ You can also use WebMock without RSpec or Test::Unit support:
96
141
 
97
142
  RestClient.post('www.example.net', 'abc') # ===> "abc\n"
98
143
 
99
- ### Request with basic authentication
144
+ ### Multiple responses for repeated requests
100
145
 
101
- stub_request(:get, "user:pass@www.example.com")
146
+ stub_request(:get, "www.example.com").to_return({:body => "abc"}, {:body => "def"})
147
+ Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
148
+ Net::HTTP.get('www.example.com', '/') # ===> "def\n"
149
+
150
+ #after all responses are used the last response will be returned infinitely
151
+
152
+ Net::HTTP.get('www.example.com', '/') # ===> "def\n"
102
153
 
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
154
+ ### Multiple responses using chained `to_return()` or `to_raise()` declarations
108
155
 
109
- ### Matching uris using regular expressions
156
+ stub_request(:get, "www.example.com").
157
+ to_return({:body => "abc"}).then. #then() just is a syntactic sugar
158
+ to_return({:body => "def"}).then.
159
+ to_raise(MyException)
160
+ Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
161
+ Net::HTTP.get('www.example.com', '/') # ===> "def\n"
162
+ Net::HTTP.get('www.example.com', '/') # ===> MyException raised
110
163
 
111
- stub_request(:any, /.*example.*/)
164
+ ### Specifying number of times given response should be returned
165
+
166
+ stub_request(:get, "www.example.com").
167
+ to_return({:body => "abc"}).times(2).then.
168
+ to_return({:body => "def"})
169
+
170
+ Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
171
+ Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
172
+ Net::HTTP.get('www.example.com', '/') # ===> "def\n"
112
173
 
113
- Net::HTTP.get('www.example.com', '/') # ===> Success
114
174
 
115
175
  ### Real requests to network can be allowed or disabled
116
176
 
@@ -146,6 +206,8 @@ You can also use WebMock without RSpec or Test::Unit support:
146
206
 
147
207
  assert_not_requested :get, "http://www.something.com" # ===> Success
148
208
 
209
+ assert_requested(:post, "http://www.example.com", :times => 1) { |req| req.body == "abc" }
210
+
149
211
  ### Expecting real (not stubbed) requests
150
212
 
151
213
  WebMock.allow_net_connect!
@@ -163,6 +225,8 @@ You can also use WebMock without RSpec or Test::Unit support:
163
225
  WebMock.should have_requested(:get, "www.example.com").with(:body => "abc", :headers => {'Content-Length' => 3}).twice
164
226
 
165
227
  WebMock.should_not have_requested(:get, "www.something.com")
228
+
229
+ WebMock.should have_requested(:post, "www.example.com").with { |req| req.body == "abc" }
166
230
 
167
231
  ### Different way of setting expectations in RSpec
168
232
 
@@ -172,7 +236,8 @@ You can also use WebMock without RSpec or Test::Unit support:
172
236
 
173
237
  request(:any, "www.example.com").should_not have_been_made
174
238
 
175
-
239
+ request(:post, "www.example.com").with { |req| req.body == "abc" }.should have_been_made
240
+
176
241
  ## Clearing stubs and request history
177
242
 
178
243
  If you want to reset all current stubs and history of requests use `WebMock.reset_webmock`
@@ -195,7 +260,8 @@ An executed request matches stubbed request if it passes following criteria:
195
260
  When request URI matches stubbed request URI string or Regexp pattern<br/>
196
261
  And request method is the same as stubbed request method or stubbed request method is :any<br/>
197
262
  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
263
+ 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/>
264
+ And request matches provided block or block is not provided
199
265
 
200
266
  ## Precedence of stubs
201
267
 
@@ -299,4 +365,4 @@ I also preferred some things to work differently i.e request stub precedence.
299
365
 
300
366
  ## Copyright
301
367
 
302
- Copyright 2009 Bartosz Blimke. See LICENSE for details.
368
+ Copyright 2009-2010 Bartosz Blimke. See LICENSE for details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.8.2
1
+ 0.9.0
@@ -14,6 +14,7 @@ require 'webmock/util/hash_counter'
14
14
  require 'webmock/request'
15
15
  require 'webmock/request_profile'
16
16
  require 'webmock/request_signature'
17
+ require 'webmock/responses_sequence'
17
18
  require 'webmock/request_stub'
18
19
  require 'webmock/response'
19
20
 
@@ -16,8 +16,8 @@ module WebMock
16
16
  self
17
17
  end
18
18
 
19
- def with(options)
20
- @request_execution_verifier.request_profile.with(options)
19
+ def with(options = {}, &block)
20
+ @request_execution_verifier.request_profile.with(options, &block)
21
21
  self
22
22
  end
23
23
 
@@ -69,12 +69,19 @@ module Net #:nodoc: all
69
69
  method = request.method.downcase.to_sym
70
70
 
71
71
  headers = Hash[*request.to_hash.map {|k,v| [k, v.flatten]}.flatten]
72
-
73
- remove_default_net_http_headers!(headers)
74
-
72
+
75
73
  headers.reject! {|k,v| k =~ /[Aa]uthorization/ && v =~ /^Basic / } #we added it to url userinfo
76
74
 
77
- request.set_body_internal body
75
+ if request.body_stream
76
+ body = request.body_stream.read
77
+ request.body_stream = nil
78
+ end
79
+
80
+ if body != nil && body.respond_to?(:read)
81
+ request.set_body_internal body.read
82
+ else
83
+ request.set_body_internal body
84
+ end
78
85
 
79
86
  request_signature = WebMock::RequestSignature.new(method, uri, :body => request.body, :headers => headers)
80
87
 
@@ -122,15 +129,6 @@ module Net #:nodoc: all
122
129
  response
123
130
  end
124
131
 
125
- def remove_default_net_http_headers!(headers)
126
- default_request = Net::HTTPGenericRequest.new('','','','/')
127
- default_net_http_headers = Hash[*default_request.to_hash.map {|k,v|
128
- [k, v.flatten]
129
- }.flatten]
130
- headers.reject! {|k,v| default_request[k] == v}
131
- headers
132
- end
133
-
134
132
  end
135
133
 
136
134
  end
@@ -14,7 +14,7 @@ module WebMock
14
14
  string << " with body '#{body.to_s}'" if body && body.to_s != ''
15
15
  if headers && !headers.empty?
16
16
  string << " with headers #{WebMock::Util::Headers.normalize_headers(headers).inspect.gsub("\"","'")}"
17
- end
17
+ end
18
18
  string
19
19
  end
20
20
 
@@ -1,15 +1,24 @@
1
1
  module WebMock
2
2
 
3
3
  class RequestProfile < Request
4
+
5
+ attr_reader :with_block
4
6
 
5
- def with(options)
7
+ def with(options = {}, &block)
6
8
  assign_options(options)
9
+ @with_block = block
7
10
  self
8
11
  end
9
12
 
10
13
  def body=(body)
11
14
  @body = Body.new(body)
12
15
  end
16
+
17
+ def to_s
18
+ string = super
19
+ string << " with given block" if @with_block
20
+ string
21
+ end
13
22
 
14
23
  class Body
15
24
 
@@ -22,7 +31,7 @@ module WebMock
22
31
  def ==(other)
23
32
  other = Body.new(other) unless other.is_a?(Body)
24
33
  other.is_a?(Body) &&
25
- (other.is_empty? && self.is_empty? || other.data == self.data)
34
+ (other.is_empty? && self.is_empty? || other.data == self.data || self.data === other.data )
26
35
  end
27
36
 
28
37
  def is_empty?
@@ -7,7 +7,8 @@ module WebMock
7
7
  match_method(request_profile) &&
8
8
  match_body(request_profile) &&
9
9
  match_headers(request_profile) &&
10
- match_uri(request_profile)
10
+ match_uri(request_profile) &&
11
+ match_with_block(request_profile)
11
12
  end
12
13
 
13
14
  private
@@ -26,7 +27,7 @@ module WebMock
26
27
  return false if self.headers && !self.headers.empty? && request_profile.headers && request_profile.headers.empty?
27
28
  if request_profile.headers && !request_profile.headers.empty?
28
29
  request_profile.headers.each do | key, value |
29
- return false unless (self.headers && self.headers.has_key?(key) && value == self.headers[key])
30
+ return false unless (self.headers && self.headers.has_key?(key) && value === self.headers[key])
30
31
  end
31
32
  end
32
33
  return true
@@ -39,6 +40,11 @@ module WebMock
39
40
  def match_method(request_profile)
40
41
  request_profile.method == self.method || request_profile.method == :any
41
42
  end
43
+
44
+ def match_with_block(request_profile)
45
+ return true unless request_profile.with_block
46
+ request_profile.with_block.call(self)
47
+ end
42
48
  end
43
49
 
44
50
 
@@ -1,25 +1,53 @@
1
1
  module WebMock
2
2
  class RequestStub
3
- attr_accessor :request_profile, :response
4
-
3
+
4
+ attr_accessor :request_profile, :responses
5
+
5
6
  def initialize(method, uri)
6
7
  @request_profile = RequestProfile.new(method, uri)
7
- @response = WebMock::Response.new
8
+ @responses_sequences = []
9
+ self
10
+ end
11
+
12
+ def with(params = {}, &block)
13
+ @request_profile.with(params, &block)
14
+ self
15
+ end
16
+
17
+ def to_return(*response_hashes)
18
+ @responses_sequences << ResponsesSequence.new([*response_hashes].flatten.map {|r| WebMock::Response.new(r)})
8
19
  self
9
20
  end
10
21
 
11
- def with(params)
12
- @request_profile.with(params)
22
+ def to_raise(*exceptions)
23
+ @responses_sequences << ResponsesSequence.new([*exceptions].flatten.map {|e| WebMock::Response.new(:exception => e)})
13
24
  self
14
25
  end
15
26
 
16
- def to_return(response_hash)
17
- @response = WebMock::Response.new(response_hash)
27
+ def response
28
+ if @responses_sequences.empty?
29
+ WebMock::Response.new
30
+ elsif @responses_sequences.length > 1
31
+ @responses_sequences.shift if @responses_sequences.first.end?
32
+ @responses_sequences.first.next_response
33
+ else
34
+ @responses_sequences[0].next_response
35
+ end
18
36
  end
19
-
20
- def to_raise(exception)
21
- @response = WebMock::Response.new({:exception => exception})
37
+
38
+ def then
39
+ self
22
40
  end
23
-
41
+
42
+ def times(number)
43
+ raise "times(N) accepts integers >= 1 only" if !number.is_a?(Fixnum) || number < 1
44
+ if @responses_sequences.empty?
45
+ raise "Invalid WebMock stub declaration." +
46
+ " times(N) can be declared only after response declaration."
47
+ end
48
+ @responses_sequences.last.times_to_repeat += number-1
49
+ self
50
+ end
51
+
24
52
  end
25
53
  end