webmock 0.7.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.
- 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
|