webmock 1.6.2 → 1.6.4

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