webmock 0.8.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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