webmock 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +21 -0
- data/LICENSE +281 -0
- data/README.md +170 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/lib/webmock.rb +18 -0
- data/lib/webmock/adapters/rspec.rb +23 -0
- data/lib/webmock/adapters/rspec/matchers.rb +19 -0
- data/lib/webmock/adapters/rspec/request_profile_matcher.rb +37 -0
- data/lib/webmock/adapters/rspec/webmock_matcher.rb +45 -0
- data/lib/webmock/adapters/test_unit.rb +25 -0
- data/lib/webmock/config.rb +7 -0
- data/lib/webmock/errors.rb +5 -0
- data/lib/webmock/http_lib_adapters/net_http.rb +129 -0
- data/lib/webmock/request_execution_verifier.rb +22 -0
- data/lib/webmock/request_profile.rb +67 -0
- data/lib/webmock/request_registry.rb +47 -0
- data/lib/webmock/request_stub.rb +26 -0
- data/lib/webmock/response.rb +31 -0
- data/lib/webmock/url.rb +46 -0
- data/lib/webmock/util/hash_counter.rb +12 -0
- data/lib/webmock/utility.rb +65 -0
- data/lib/webmock/webmock.rb +58 -0
- data/spec/net_http_spec.rb +33 -0
- data/spec/other_net_http_libs_spec.rb +37 -0
- data/spec/request_execution_verifier_spec.rb +51 -0
- data/spec/request_profile_spec.rb +166 -0
- data/spec/request_registry_spec.rb +114 -0
- data/spec/request_stub_spec.rb +54 -0
- data/spec/response_spec.rb +59 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +58 -0
- data/spec/util/hash_counter_spec.rb +24 -0
- data/spec/utility_spec.rb +70 -0
- data/spec/vendor/right_http_connection-1.2.4/History.txt +59 -0
- data/spec/vendor/right_http_connection-1.2.4/Manifest.txt +7 -0
- data/spec/vendor/right_http_connection-1.2.4/README.txt +54 -0
- data/spec/vendor/right_http_connection-1.2.4/Rakefile +103 -0
- data/spec/vendor/right_http_connection-1.2.4/lib/net_fix.rb +160 -0
- data/spec/vendor/right_http_connection-1.2.4/lib/right_http_connection.rb +435 -0
- data/spec/vendor/right_http_connection-1.2.4/setup.rb +1585 -0
- data/spec/vendor/samuel-0.2.1/.document +5 -0
- data/spec/vendor/samuel-0.2.1/.gitignore +5 -0
- data/spec/vendor/samuel-0.2.1/LICENSE +20 -0
- data/spec/vendor/samuel-0.2.1/README.rdoc +70 -0
- data/spec/vendor/samuel-0.2.1/Rakefile +62 -0
- data/spec/vendor/samuel-0.2.1/VERSION +1 -0
- data/spec/vendor/samuel-0.2.1/lib/samuel.rb +52 -0
- data/spec/vendor/samuel-0.2.1/lib/samuel/net_http.rb +10 -0
- data/spec/vendor/samuel-0.2.1/lib/samuel/request.rb +96 -0
- data/spec/vendor/samuel-0.2.1/samuel.gemspec +69 -0
- data/spec/vendor/samuel-0.2.1/test/request_test.rb +193 -0
- data/spec/vendor/samuel-0.2.1/test/samuel_test.rb +42 -0
- data/spec/vendor/samuel-0.2.1/test/test_helper.rb +66 -0
- data/spec/vendor/samuel-0.2.1/test/thread_test.rb +32 -0
- data/spec/webmock_spec.rb +492 -0
- data/test/test_helper.rb +9 -0
- data/test/test_webmock.rb +56 -0
- metadata +144 -0
data/Rakefile
ADDED
@@ -0,0 +1,54 @@
|
|
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_development_dependency "rspec", ">= 1.2.9"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'spec/rake/spectask'
|
22
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
23
|
+
spec.libs << 'lib' << 'spec'
|
24
|
+
spec.spec_files = FileList['spec/**/*_spec.rb'].exclude("spec/vendor")
|
25
|
+
end
|
26
|
+
|
27
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
28
|
+
spec.libs << 'lib' << 'spec'
|
29
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
30
|
+
spec.rcov = true
|
31
|
+
end
|
32
|
+
|
33
|
+
require 'rake/testtask'
|
34
|
+
Rake::TestTask.new(:test) do |test|
|
35
|
+
test.test_files = FileList["test/**/*.rb"].exclude("test/test_helper.rb")
|
36
|
+
test.verbose = false
|
37
|
+
test.warning = true
|
38
|
+
end
|
39
|
+
|
40
|
+
task :spec => :check_dependencies
|
41
|
+
|
42
|
+
task :test => :check_dependencies
|
43
|
+
|
44
|
+
task :default => [:spec, :test]
|
45
|
+
|
46
|
+
require 'rake/rdoctask'
|
47
|
+
Rake::RDocTask.new do |rdoc|
|
48
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
49
|
+
|
50
|
+
rdoc.rdoc_dir = 'rdoc'
|
51
|
+
rdoc.title = "webmock #{version}"
|
52
|
+
rdoc.rdoc_files.include('README*')
|
53
|
+
rdoc.rdoc_files.include('lib/webmock/webmock.rb')
|
54
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.7.0
|
data/lib/webmock.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
require 'webmock/http_lib_adapters/net_http'
|
4
|
+
|
5
|
+
require 'webmock/errors'
|
6
|
+
require 'webmock/request_profile'
|
7
|
+
require 'webmock/request_execution_verifier'
|
8
|
+
require 'webmock/url'
|
9
|
+
require 'webmock/request_stub'
|
10
|
+
require 'webmock/utility'
|
11
|
+
require 'webmock/config'
|
12
|
+
require 'webmock/response'
|
13
|
+
require 'webmock/util/hash_counter'
|
14
|
+
require 'webmock/request_registry'
|
15
|
+
require 'webmock/webmock'
|
16
|
+
|
17
|
+
require 'webmock/adapters/rspec'
|
18
|
+
require 'webmock/adapters/test_unit'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
if defined?(Spec::Runner)
|
2
|
+
|
3
|
+
require 'webmock/adapters/rspec/request_profile_matcher'
|
4
|
+
require 'webmock/adapters/rspec/webmock_matcher'
|
5
|
+
require 'webmock/adapters/rspec/matchers'
|
6
|
+
|
7
|
+
Spec::Runner.configure { |config|
|
8
|
+
|
9
|
+
config.include WebMock::Matchers
|
10
|
+
|
11
|
+
config.before :each do
|
12
|
+
WebMock.reset_webmock
|
13
|
+
end
|
14
|
+
}
|
15
|
+
|
16
|
+
module WebMock
|
17
|
+
private
|
18
|
+
def assertion_failure(message)
|
19
|
+
raise Spec::Expectations::ExpectationNotMetError.new(message)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module WebMock
|
2
|
+
module Matchers
|
3
|
+
def have_been_made
|
4
|
+
WebMock::RequestProfileMatcher.new
|
5
|
+
end
|
6
|
+
|
7
|
+
def have_not_been_made
|
8
|
+
WebMock::RequestProfileMatcher.new.times(0)
|
9
|
+
end
|
10
|
+
|
11
|
+
def have_requested(method, url)
|
12
|
+
WebMock::WebMockMatcher.new(method, url)
|
13
|
+
end
|
14
|
+
|
15
|
+
def have_not_requested(method, url)
|
16
|
+
WebMock::WebMockMatcher.new(method, url).times(0)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module WebMock
|
2
|
+
class RequestProfileMatcher
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@request_execution_verifier = RequestExecutionVerifier.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def once
|
9
|
+
@request_execution_verifier.expected_times_executed = 1
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
def twice
|
14
|
+
@request_execution_verifier.expected_times_executed = 2
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def times(times)
|
19
|
+
@request_execution_verifier.expected_times_executed = times.to_i
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def matches?(request_profile)
|
24
|
+
@request_execution_verifier.request_profile = request_profile
|
25
|
+
@request_execution_verifier.verify
|
26
|
+
end
|
27
|
+
|
28
|
+
def failure_message
|
29
|
+
@request_execution_verifier.failure_message
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def negative_failure_message
|
34
|
+
@request_execution_verifier.negative_failure_message
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module WebMock
|
2
|
+
class WebMockMatcher
|
3
|
+
|
4
|
+
def initialize(method, url)
|
5
|
+
@request_execution_verifier = RequestExecutionVerifier.new
|
6
|
+
@request_execution_verifier.request_profile = RequestProfile.new(method, url)
|
7
|
+
end
|
8
|
+
|
9
|
+
def once
|
10
|
+
@request_execution_verifier.expected_times_executed = 1
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def twice
|
15
|
+
@request_execution_verifier.expected_times_executed = 2
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
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)
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def times(times)
|
28
|
+
@request_execution_verifier.expected_times_executed = times.to_i
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def matches?(webmock)
|
33
|
+
@request_execution_verifier.verify
|
34
|
+
end
|
35
|
+
|
36
|
+
def failure_message
|
37
|
+
@request_execution_verifier.failure_message
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def negative_failure_message
|
42
|
+
@request_execution_verifier.negative_failure_message
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
if defined?(Test::Unit::TestCase)
|
2
|
+
|
3
|
+
class Test::Unit::TestCase
|
4
|
+
include WebMock
|
5
|
+
alias setup_without_webmock setup
|
6
|
+
def setup
|
7
|
+
reset_webmock
|
8
|
+
@original_allow_net_connect = WebMock.net_connect_allowed?
|
9
|
+
WebMock.disable_net_connect!
|
10
|
+
end
|
11
|
+
|
12
|
+
alias teardown_without_webmock teardown
|
13
|
+
def teardown
|
14
|
+
@original_allow_net_connect ? WebMock.allow_net_connect! : WebMock.disable_net_connect!
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module WebMock
|
19
|
+
private
|
20
|
+
def assertion_failure(message)
|
21
|
+
raise Test::Unit::AssertionFailedError.new(message)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
|
6
|
+
class StubSocket #:nodoc:
|
7
|
+
|
8
|
+
def initialize(*args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def closed?
|
12
|
+
@closed ||= true
|
13
|
+
end
|
14
|
+
|
15
|
+
def readuntil(*args)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
module StubResponse
|
21
|
+
def read_body(*args, &block)
|
22
|
+
yield @body if block_given?
|
23
|
+
@body
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module Net #:nodoc: all
|
28
|
+
|
29
|
+
class BufferedIO
|
30
|
+
def initialize_with_webmock(io, debug_output = nil)
|
31
|
+
@read_timeout = 60
|
32
|
+
@rbuf = ''
|
33
|
+
@debug_output = debug_output
|
34
|
+
|
35
|
+
@io = case io
|
36
|
+
when Socket, OpenSSL::SSL::SSLSocket, IO
|
37
|
+
io
|
38
|
+
when String
|
39
|
+
if !io.include?("\0") && File.exists?(io) && !File.directory?(io)
|
40
|
+
File.open(io, "r")
|
41
|
+
else
|
42
|
+
StringIO.new(io)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
raise "Unable to create local socket" unless @io
|
46
|
+
end
|
47
|
+
alias_method :initialize_without_webmock, :initialize
|
48
|
+
alias_method :initialize, :initialize_with_webmock
|
49
|
+
end
|
50
|
+
|
51
|
+
class HTTP
|
52
|
+
class << self
|
53
|
+
def socket_type_with_webmock
|
54
|
+
StubSocket
|
55
|
+
end
|
56
|
+
alias_method :socket_type_without_webmock, :socket_type
|
57
|
+
alias_method :socket_type, :socket_type_with_webmock
|
58
|
+
end
|
59
|
+
|
60
|
+
def request_with_webmock(request, body = nil, &block)
|
61
|
+
protocol = use_ssl? ? "https" : "http"
|
62
|
+
|
63
|
+
path = request.path
|
64
|
+
path = URI.parse(request.path).request_uri if request.path =~ /^http/
|
65
|
+
|
66
|
+
if request["authorization"] =~ /^Basic /
|
67
|
+
userinfo = WebMock::Utility.decode_userinfo_from_header(request["authorization"])
|
68
|
+
userinfo = WebMock::Utility.encode_unsafe_chars_in_userinfo(userinfo) + "@"
|
69
|
+
else
|
70
|
+
userinfo = ""
|
71
|
+
end
|
72
|
+
|
73
|
+
uri = "#{protocol}://#{userinfo}#{self.address}:#{self.port}#{path}"
|
74
|
+
method = request.method.downcase.to_sym
|
75
|
+
|
76
|
+
headers = Hash[*request.to_hash.map {|k,v| [k, v.flatten]}.flatten]
|
77
|
+
headers.reject! {|k,v| k =~ /[Aa]ccept/ && v = '*/*'}
|
78
|
+
|
79
|
+
request_profile = WebMock::RequestProfile.new(method, uri, body, headers)
|
80
|
+
|
81
|
+
if WebMock.registered_request?(request_profile)
|
82
|
+
@socket = Net::HTTP.socket_type.new
|
83
|
+
webmock_response = WebMock.response_for_request(request_profile)
|
84
|
+
build_net_http_response(webmock_response, &block)
|
85
|
+
elsif WebMock.net_connect_allowed?
|
86
|
+
WebMock::RequestRegistry.instance.requested.put(request_profile)
|
87
|
+
connect_without_webmock
|
88
|
+
request_without_webmock(request, body, &block)
|
89
|
+
else
|
90
|
+
uri = WebMock::Utility.strip_default_port_from_uri(uri)
|
91
|
+
message = "Real HTTP connections are disabled. Unregistered request: #{request.method} #{uri}"
|
92
|
+
message << " with body '#{body}'" if body
|
93
|
+
message << " with headers #{WebMock::Utility.normalize_headers(headers).inspect.gsub("\"","'")}" if
|
94
|
+
headers && !headers.empty?
|
95
|
+
raise WebMock::NetConnectNotAllowedError, message
|
96
|
+
end
|
97
|
+
end
|
98
|
+
alias_method :request_without_webmock, :request
|
99
|
+
alias_method :request, :request_with_webmock
|
100
|
+
|
101
|
+
|
102
|
+
def connect_with_webmock
|
103
|
+
unless @@alredy_checked_for_net_http_replacement_libs ||= false
|
104
|
+
WebMock::Utility.puts_warning_for_net_http_replacement_libs_if_needed
|
105
|
+
@@alredy_checked_for_net_http_replacement_libs = true
|
106
|
+
end
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
alias_method :connect_without_webmock, :connect
|
110
|
+
alias_method :connect, :connect_with_webmock
|
111
|
+
|
112
|
+
def build_net_http_response(webmock_response, &block)
|
113
|
+
response = Net::HTTPResponse.send(:response_class, webmock_response.status.to_s).new("1.0", webmock_response.status.to_s, "")
|
114
|
+
response.instance_variable_set(:@body, webmock_response.body)
|
115
|
+
webmock_response.headers.to_a.each { |name, value| response[name] = value }
|
116
|
+
|
117
|
+
response.instance_variable_set(:@read, true)
|
118
|
+
|
119
|
+
response.extend StubResponse
|
120
|
+
|
121
|
+
webmock_response.raise_error_if_any
|
122
|
+
|
123
|
+
yield response if block_given?
|
124
|
+
|
125
|
+
response
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module WebMock
|
2
|
+
class RequestExecutionVerifier
|
3
|
+
|
4
|
+
attr_accessor :request_profile, :expected_times_executed, :times_executed
|
5
|
+
|
6
|
+
def initialize(request_profile = nil, expected_times_executed = nil)
|
7
|
+
@request_profile = request_profile
|
8
|
+
@expected_times_executed = expected_times_executed || 1
|
9
|
+
end
|
10
|
+
|
11
|
+
def verify
|
12
|
+
@times_executed =
|
13
|
+
RequestRegistry.instance.times_executed(@request_profile)
|
14
|
+
@times_executed == @expected_times_executed
|
15
|
+
end
|
16
|
+
|
17
|
+
def failure_message
|
18
|
+
%Q(The request #{request_profile.to_s} was expected to execute #{expected_times_executed} time#{ (expected_times_executed == 1) ? '' : 's'} but it executed #{times_executed} time#{ (times_executed == 1) ? '' : 's'})
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module WebMock
|
2
|
+
|
3
|
+
class RequestProfile < Struct.new(:method, :uri, :body, :headers)
|
4
|
+
|
5
|
+
def initialize(method, uri, body = nil, headers = nil)
|
6
|
+
super
|
7
|
+
self.uri = WebMock::URL.normalize_uri(self.uri) unless self.uri.is_a?(URI)
|
8
|
+
self.headers = Utility.normalize_headers(self.headers)
|
9
|
+
end
|
10
|
+
|
11
|
+
def with(options)
|
12
|
+
self.body = options[:body] if options.has_key?(:body)
|
13
|
+
self.headers = Utility.normalize_headers(options[:headers]) if options.has_key?(:headers)
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
#self needs to be a subset of other. Other needs to be more general.
|
18
|
+
def match(other)
|
19
|
+
match_method(other) &&
|
20
|
+
match_body(other) &&
|
21
|
+
match_headers(other) &&
|
22
|
+
match_url(other)
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
string = "#{self.method.to_s.upcase} #{self.uri}"
|
27
|
+
string << " with body '#{body}'" if body
|
28
|
+
if headers && !headers.empty?
|
29
|
+
string << " with headers #{WebMock::Utility.normalize_headers(headers).inspect.gsub("\"","'")}"
|
30
|
+
end
|
31
|
+
string
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def match_url(other)
|
37
|
+
raise "Can't match regexp request profile" if self.uri.is_a?(Regexp)
|
38
|
+
@uris_to_check ||= WebMock::URL.variations_of_uri_as_strings(self.uri)
|
39
|
+
if other.uri.is_a?(URI)
|
40
|
+
@uris_to_check.include?(other.uri.to_s)
|
41
|
+
elsif other.uri.is_a?(Regexp)
|
42
|
+
@uris_to_check.any? { |u| u.match(other.uri) }
|
43
|
+
else
|
44
|
+
false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def match_headers(other)
|
49
|
+
return false if self.headers && !self.headers.empty? && other.headers && other.headers.empty?
|
50
|
+
if other.headers && !other.headers.empty?
|
51
|
+
other.headers.each do | key, value |
|
52
|
+
return false unless (self.headers && self.headers.has_key?(key) && value == self.headers[key])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
return true
|
56
|
+
end
|
57
|
+
|
58
|
+
def match_body(other)
|
59
|
+
other.body == self.body || other.body.nil?
|
60
|
+
end
|
61
|
+
|
62
|
+
def match_method(other)
|
63
|
+
other.method == self.method || other.method == :any
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|