webmock 1.6.2 → 1.6.4

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/Rakefile CHANGED
@@ -1,31 +1,20 @@
1
- require 'rubygems'
2
- require 'rake'
3
-
4
- begin
5
- require 'jeweler'
6
- Jeweler::Tasks.new do |gem|
7
- gem.name = "webmock"
8
- gem.summary = %Q{Library for stubbing HTTP requests in Ruby.}
9
- gem.description = %Q{WebMock allows stubbing HTTP requests and setting expectations on HTTP requests.}
10
- gem.email = "bartosz.blimke@gmail.com"
11
- gem.homepage = "http://github.com/bblimke/webmock"
12
- gem.authors = ["Bartosz Blimke"]
13
- gem.add_dependency "addressable", ">= 2.2.2"
14
- gem.add_dependency "crack", ">=0.1.7"
15
- gem.add_development_dependency "rspec", ">= 2.0.0"
16
- gem.add_development_dependency "httpclient", ">= 2.1.5.2"
17
- gem.add_development_dependency "patron", ">= 0.4.9" unless RUBY_PLATFORM =~ /java/
18
- gem.add_development_dependency "em-http-request", ">= 0.2.14" unless RUBY_PLATFORM =~ /java/
19
- gem.add_development_dependency "curb", ">= 0.7.8" unless RUBY_PLATFORM =~ /java/
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ namespace :spec do
5
+ desc 'Run specs against 1.8.6, REE, 1.8.7, 1.9.2 and jRuby'
6
+ task :rubies do
7
+ # JCF: I'd love to be able to use RVM's `rvm {rubies} specs` command but
8
+ # the require tests in spec/other_net_http_libs_spec.rb break when doing
9
+ # so.
10
+ spec_files = Dir[File.dirname(__FILE__) + '/spec/**/*_spec.rb'].join(' ')
11
+ sh "rvm 1.8.6@webmock,ree@webmock,1.8.7@webmock,1.9.2@webmock,jruby@webmock exec rspec #{spec_files}"
20
12
  end
21
- Jeweler::GemcutterTasks.new
22
- rescue LoadError
23
- puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
24
13
  end
25
14
 
26
15
  require "rspec/core/rake_task"
27
16
  RSpec::Core::RakeTask.new do |t|
28
- t.rspec_opts = ["-c", "-f progress", "-r ./spec/spec_helper.rb"]
17
+ t.rspec_opts = ["-c", "-f progress", "-r ./spec/spec_helper.rb"]
29
18
  t.pattern = 'spec/**/*_spec.rb'
30
19
  end
31
20
 
@@ -36,18 +25,15 @@ Rake::TestTask.new(:test) do |test|
36
25
  test.warning = false
37
26
  end
38
27
 
39
- task :spec => :check_dependencies
40
-
41
- task :test => :check_dependencies
42
-
43
28
  task :default => [:spec, :test]
44
29
 
45
30
  require 'rake/rdoctask'
46
31
  Rake::RDocTask.new do |rdoc|
47
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
32
+ $:.push File.expand_path('../lib', __FILE__)
33
+ require 'webmock/version'
48
34
 
49
35
  rdoc.rdoc_dir = 'rdoc'
50
- rdoc.title = "webmock #{version}"
36
+ rdoc.title = "webmock #{WebMock::VERSION}"
51
37
  rdoc.rdoc_files.include('README*')
52
38
  rdoc.rdoc_files.include('lib/webmock/webmock.rb')
53
39
  end
data/lib/webmock.rb CHANGED
@@ -4,6 +4,7 @@ require 'addressable/uri'
4
4
  require 'crack'
5
5
 
6
6
  require 'webmock/deprecation'
7
+ require 'webmock/version'
7
8
 
8
9
  require 'webmock/http_lib_adapters/net_http'
9
10
  require 'webmock/http_lib_adapters/httpclient'
@@ -33,4 +34,4 @@ require 'webmock/callback_registry'
33
34
  require 'webmock/request_registry'
34
35
  require 'webmock/stub_registry'
35
36
  require 'webmock/api'
36
- require 'webmock/webmock'
37
+ require 'webmock/webmock'
@@ -65,7 +65,28 @@ if defined?(Curl)
65
65
  @header_str << webmock_response.headers.map do |k,v|
66
66
  "#{k}: #{v.is_a?(Array) ? v.join(", ") : v}"
67
67
  end.join("\r\n")
68
+
69
+ location = webmock_response.headers['Location']
70
+ if self.follow_location? && location
71
+ @last_effective_url = location
72
+ webmock_follow_location(location)
73
+ end
74
+
75
+ @content_type = webmock_response.headers["Content-Type"]
76
+ end
77
+
78
+ @last_effective_url ||= self.url
79
+ end
80
+
81
+ def webmock_follow_location(location)
82
+ first_url = self.url
83
+ self.url = location
84
+
85
+ curb_or_webmock do
86
+ send( "http_#{@webmock_method}_without_webmock" )
68
87
  end
88
+
89
+ self.url = first_url
69
90
  end
70
91
 
71
92
  def invoke_curb_callbacks
@@ -194,6 +215,18 @@ if defined?(Curl)
194
215
  alias :header_str_without_webmock :header_str
195
216
  alias :header_str :header_str_with_webmock
196
217
 
218
+ def last_effective_url_with_webmock
219
+ @last_effective_url || last_effective_url_without_webmock
220
+ end
221
+ alias :last_effective_url_without_webmock :last_effective_url
222
+ alias :last_effective_url :last_effective_url_with_webmock
223
+
224
+ def content_type_with_webmock
225
+ @content_type || content_type_without_webmock
226
+ end
227
+ alias :content_type_without_webmock :content_type
228
+ alias :content_type :content_type_with_webmock
229
+
197
230
  %w[ success failure header body complete progress ].each do |callback|
198
231
  class_eval <<-METHOD, __FILE__, __LINE__
199
232
  def on_#{callback}_with_webmock &block
@@ -113,6 +113,13 @@ if defined?(EventMachine::HttpRequest)
113
113
 
114
114
  headers.each do |header, value|
115
115
  value = value.join(", ") if value.is_a?(Array)
116
+
117
+ # WebMock's internal processing will not handle the body
118
+ # correctly if the header indicates that it is chunked, unless
119
+ # we also create all the chunks.
120
+ # It's far easier just to remove the header.
121
+ next if header =~ /transfer-encoding/i && value =~/chunked/i
122
+
116
123
  response_string << "#{header}: #{value}"
117
124
  end if headers
118
125
 
@@ -119,7 +119,7 @@ if defined?(::HTTPClient)
119
119
  request_signature = WebMock::RequestSignature.new(
120
120
  req.header.request_method.downcase.to_sym,
121
121
  uri.to_s,
122
- :body => req.body.content,
122
+ :body => req.content,
123
123
  :headers => headers
124
124
  )
125
125
  end
@@ -143,11 +143,11 @@ module WebMock
143
143
 
144
144
  case BODY_FORMATS[content_type]
145
145
  when :json then
146
- Crack::JSON.parse(body) == @pattern
146
+ matching_hashes?(Crack::JSON.parse(body), @pattern)
147
147
  when :xml then
148
- Crack::XML.parse(body) == @pattern
148
+ matching_hashes?(Crack::XML.parse(body), @pattern)
149
149
  else
150
- Addressable::URI.parse('?' + body).query_values == @pattern
150
+ matching_hashes?(Addressable::URI.parse('?' + body).query_values, @pattern)
151
151
  end
152
152
  else
153
153
  empty_string?(@pattern) && empty_string?(body) ||
@@ -162,6 +162,43 @@ module WebMock
162
162
 
163
163
  private
164
164
 
165
+ # Compare two hashes for equality
166
+ #
167
+ # For two hashes to match they must have the same length and all
168
+ # values must match when compared using `#===`.
169
+ #
170
+ # The following hashes are examples of matches:
171
+ #
172
+ # {a: /\d+/} and {a: '123'}
173
+ #
174
+ # {a: '123'} and {a: '123'}
175
+ #
176
+ # {a: {b: /\d+/}} and {a: {b: '123'}}
177
+ #
178
+ # {a: {b: 'wow'}} and {a: {b: 'wow'}}
179
+ #
180
+ # @param [Hash] query_parameters typically the result of parsing
181
+ # JSON, XML or URL encoded parameters.
182
+ #
183
+ # @param [Hash] pattern which contains keys with a string, hash or
184
+ # regular expression value to use for comparison.
185
+ #
186
+ # @return [Boolean] true if the paramaters match the comparison
187
+ # hash, false if not.
188
+ def matching_hashes?(query_parameters, pattern)
189
+ return false unless query_parameters.size == pattern.size
190
+ query_parameters.each do |key, actual|
191
+ expected = pattern[key]
192
+
193
+ if actual.is_a?(Hash) && expected.is_a?(Hash)
194
+ return false unless matching_hashes?(actual, expected)
195
+ else
196
+ return false unless expected === actual
197
+ end
198
+ end
199
+ true
200
+ end
201
+
165
202
  def empty_string?(string)
166
203
  string.nil? || string == ""
167
204
  end
@@ -0,0 +1,3 @@
1
+ module WebMock
2
+ VERSION = '1.6.4'
3
+ end
@@ -22,9 +22,7 @@ module WebMock
22
22
  end
23
23
 
24
24
  def self.version
25
- open(File.join(File.dirname(__FILE__), '../../VERSION')) { |f|
26
- f.read.strip
27
- }
25
+ VERSION
28
26
  end
29
27
 
30
28
  def self.allow_net_connect!(options = {})
data/spec/curb_spec.rb CHANGED
@@ -77,7 +77,7 @@ unless RUBY_PLATFORM =~ /java/
77
77
  test = data
78
78
  end
79
79
  @curl.http_get
80
- test.should match /One: 1/
80
+ test.should match(/One: 1/)
81
81
  end
82
82
 
83
83
  it "should call on_complete when request is complete" do
@@ -133,6 +133,124 @@ unless RUBY_PLATFORM =~ /java/
133
133
  order.should == [:on_progress,:on_header,:on_body,:on_complete,:on_failure]
134
134
  end
135
135
  end
136
+
137
+ describe '#last_effective_url' do
138
+ before(:each) do
139
+ @curl = Curl::Easy.new
140
+ @curl.url = "http://example.com"
141
+ end
142
+
143
+ context 'when not following redirects' do
144
+ before { @curl.follow_location = false }
145
+
146
+ it 'should be the same as #url even with a location header' do
147
+ stub_request(:any, 'example.com').
148
+ to_return(:body => "abc",
149
+ :status => 302,
150
+ :headers => { 'Location' => 'http://www.example.com' })
151
+
152
+ @curl.http_get
153
+ @curl.last_effective_url.should == 'http://example.com'
154
+ end
155
+ end
156
+
157
+ context 'when following redirects' do
158
+ before { @curl.follow_location = true }
159
+
160
+ it 'should be the same as #url when no location header is present' do
161
+ stub_request(:any, "example.com")
162
+ @curl.http_get
163
+ @curl.last_effective_url.should == 'http://example.com'
164
+ end
165
+
166
+ it 'should be the value of the location header when present' do
167
+ stub_request(:any, 'example.com').
168
+ to_return(:headers => { 'Location' => 'http://www.example.com' })
169
+ stub_request(:any, 'www.example.com')
170
+
171
+ @curl.http_get
172
+ @curl.last_effective_url.should == 'http://www.example.com'
173
+ end
174
+
175
+ it 'should work with more than one redirect' do
176
+ stub_request(:any, 'example.com').
177
+ to_return(:headers => { 'Location' => 'http://www.example.com' })
178
+ stub_request(:any, 'www.example.com').
179
+ to_return(:headers => { 'Location' => 'http://blog.example.com' })
180
+ stub_request(:any, 'blog.example.com')
181
+
182
+ @curl.http_get
183
+ @curl.last_effective_url.should == 'http://blog.example.com'
184
+ end
185
+
186
+ it 'should maintain the original url' do
187
+ stub_request(:any, 'example.com').
188
+ to_return(:headers => { 'Location' => 'http://www.example.com' })
189
+ stub_request(:any, 'www.example.com')
190
+
191
+ @curl.http_get
192
+ @curl.url.should == 'http://example.com'
193
+ end
194
+
195
+ it 'should have the redirected-to attrs (body, response code)' do
196
+ stub_request(:any, 'example.com').
197
+ to_return(:body => 'request A',
198
+ :status => 302,
199
+ :headers => { 'Location' => 'http://www.example.com' })
200
+ stub_request(:any, 'www.example.com').to_return(:body => 'request B')
201
+
202
+ @curl.http_get
203
+ @curl.body_str.should == 'request B'
204
+ @curl.response_code.should == 200
205
+ end
206
+
207
+ it 'should follow more than one redirect' do
208
+ stub_request(:any, 'example.com').
209
+ to_return(:headers => { 'Location' => 'http://www.example.com' })
210
+ stub_request(:any, 'www.example.com').
211
+ to_return(:headers => { 'Location' => 'http://blog.example.com' })
212
+ stub_request(:any, 'blog.example.com').to_return(:body => 'blog post')
213
+
214
+ @curl.http_get
215
+ @curl.url.should == 'http://example.com'
216
+ @curl.body_str.should == 'blog post'
217
+ end
218
+ end
219
+ end
220
+
221
+ describe "#content_type" do
222
+ before(:each) do
223
+ @curl = Curl::Easy.new
224
+ @curl.url = "http://example.com"
225
+ end
226
+
227
+ context "when response includes Content-Type header" do
228
+ it "returns correct content_type" do
229
+ content_type = "application/json"
230
+
231
+ stub_request(:any, 'example.com').
232
+ to_return(:body => "abc",
233
+ :status => 200,
234
+ :headers => { 'Content-Type' => content_type })
235
+
236
+ @curl.http_get
237
+ @curl.content_type.should == content_type
238
+ end
239
+ end
240
+
241
+ context "when response does not include Content-Type header" do
242
+ it "returns nil for content_type" do
243
+ content_type = "application/json"
244
+
245
+ stub_request(:any, 'example.com').
246
+ to_return(:body => "abc",
247
+ :status => 200 )
248
+
249
+ @curl.http_get
250
+ @curl.content_type.should be_nil
251
+ end
252
+ end
253
+ end
136
254
  end
137
255
 
138
256
  describe "Webmock with Curb" do
@@ -20,6 +20,11 @@ unless RUBY_PLATFORM =~ /java/
20
20
  response.should == "abc"
21
21
  end
22
22
 
23
+ it "should work with responses that use chunked transfer encoding" do
24
+ stub_http_request(:get, "www.example.com").to_return(:body => "abc", :headers => { 'Transfer-Encoding' => 'chunked' })
25
+ http_request(:get, "http://www.example.com").body.should == "abc"
26
+ end
27
+
23
28
  it "should work with optional query params" do
24
29
  stub_http_request(:get, "www.example.com/?x=3&a[]=b&a[]=c").to_return(:body => "abc")
25
30
  http_request(:get, "http://www.example.com/?x=3", :query => {"a" => ["b", "c"]}).body.should == "abc"
@@ -64,12 +64,16 @@ module HTTPClientSpecHelper
64
64
 
65
65
  socket.stub!(:sync=).with(true)
66
66
 
67
- socket.should_receive(:gets).with("\n").once.and_return("HTTP/1.1 #{options[:response_code]} #{options[:response_message]}\nContent-Length: #{options[:response_body].length}\n\n#{options[:response_body]}")
67
+ socket.should_receive(:gets).with("\n").
68
+ and_return("HTTP/1.1 #{options[:response_code]} #{options[:response_message]}\r\n",
69
+ "Content-Length: #{options[:response_body].length}\r\n",
70
+ "\r\n")
71
+ socket.stub(:readpartial) do |size, buf|
72
+ buf << options[:response_body]
73
+ end
68
74
 
69
75
  socket.stub!(:eof?).and_return(true)
70
76
  socket.stub!(:close).and_return(true)
71
-
72
- socket.should_receive(:readpartial).any_number_of_times.and_raise(EOFError)
73
77
  end
74
78
 
75
79
  def http_library
@@ -57,7 +57,7 @@ describe "Webmock with Net:HTTP" do
57
57
  req = Net::HTTP::Post.new("/")
58
58
  Net::HTTP.start("www.example.com") {|http|
59
59
  http.request(req, StringIO.new("my_params"))
60
- }.body.should =~ /Example Web Page/
60
+ }.body.should =~ /^$/
61
61
  end
62
62
 
63
63
  it "should handle requests with block passed to read_body", :net_connect => true do
@@ -71,7 +71,7 @@ describe "Webmock with Net:HTTP" do
71
71
  end
72
72
  end
73
73
  end
74
- body.should =~ /Example Web Page/
74
+ body.should =~ /^$/
75
75
  end
76
76
 
77
77
  it "should return a Net::ReadAdapter from response.body when a stubbed request is made with a block and #read_body" do
@@ -128,7 +128,7 @@ describe "Webmock with Net:HTTP" do
128
128
  end
129
129
 
130
130
  describe 'after_request callback support', :net_connect => true do
131
- let(:expected_body_regex) { /You have reached this web page by typing.*example\.com/ }
131
+ let(:expected_body_regex) { /^$/ }
132
132
 
133
133
  before(:each) do
134
134
  WebMock.allow_net_connect!
data/spec/patron_spec.rb CHANGED
@@ -38,9 +38,16 @@ unless RUBY_PLATFORM =~ /java/
38
38
 
39
39
  it "should raise same error as Patron if file is not readable for get request" do
40
40
  stub_http_request(:get, "www.example.com")
41
- lambda {
42
- @sess.get_file("/", "/non_existing_file")
43
- }.should raise_error(ArgumentError, "Unable to open specified file.")
41
+ File.open("/tmp/read_only_file", "w") do |tmpfile|
42
+ tmpfile.chmod(0400)
43
+ end
44
+ begin
45
+ lambda {
46
+ @sess.get_file("/", "/tmp/read_only_file")
47
+ }.should raise_error(ArgumentError, "Unable to open specified file.")
48
+ ensure
49
+ File.unlink("/tmp/read_only_file")
50
+ end
44
51
  end
45
52
 
46
53
  it "should work with put_file" do
@@ -58,7 +65,7 @@ unless RUBY_PLATFORM =~ /java/
58
65
  it "should raise same error as Patron if file is not readable for post request" do
59
66
  stub_http_request(:post, "www.example.com").with(:body => "abc")
60
67
  lambda {
61
- @sess.post_file("/", "/non_existing_file")
68
+ @sess.post_file("/", "/path/to/non/existing/file")
62
69
  }.should raise_error(ArgumentError, "Unable to open specified file.")
63
70
  end
64
71